mirror of
https://github.com/astral-sh/ruff.git
synced 2025-07-24 05:25:17 +00:00
Refactor range from Attributed
to Node
s (#4422)
This commit is contained in:
parent
140e0acf54
commit
fa26860296
330 changed files with 4816 additions and 3946 deletions
24
Cargo.lock
generated
24
Cargo.lock
generated
|
@ -1988,6 +1988,16 @@ dependencies = [
|
|||
"rustpython-parser",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ruff_source_location"
|
||||
version = "0.0.0"
|
||||
source = "git+https://github.com/RustPython/Parser.git?rev=718354673eb2cc9645d63fc0c50b4ad08e5595c2#718354673eb2cc9645d63fc0c50b4ad08e5595c2"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
"once_cell",
|
||||
"ruff_text_size",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ruff_testing_macros"
|
||||
version = "0.0.0"
|
||||
|
@ -2001,7 +2011,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "ruff_text_size"
|
||||
version = "0.0.0"
|
||||
source = "git+https://github.com/RustPython/Parser.git?rev=a983f4383fb1ad8c1c66acb1d5b0016e59f95a49#a983f4383fb1ad8c1c66acb1d5b0016e59f95a49"
|
||||
source = "git+https://github.com/RustPython/Parser.git?rev=718354673eb2cc9645d63fc0c50b4ad08e5595c2#718354673eb2cc9645d63fc0c50b4ad08e5595c2"
|
||||
dependencies = [
|
||||
"schemars",
|
||||
"serde",
|
||||
|
@ -2072,17 +2082,18 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "rustpython-ast"
|
||||
version = "0.2.0"
|
||||
source = "git+https://github.com/RustPython/Parser.git?rev=a983f4383fb1ad8c1c66acb1d5b0016e59f95a49#a983f4383fb1ad8c1c66acb1d5b0016e59f95a49"
|
||||
source = "git+https://github.com/RustPython/Parser.git?rev=718354673eb2cc9645d63fc0c50b4ad08e5595c2#718354673eb2cc9645d63fc0c50b4ad08e5595c2"
|
||||
dependencies = [
|
||||
"is-macro",
|
||||
"num-bigint",
|
||||
"rustpython-parser-core",
|
||||
"static_assertions",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustpython-format"
|
||||
version = "0.2.0"
|
||||
source = "git+https://github.com/RustPython/Parser.git?rev=a983f4383fb1ad8c1c66acb1d5b0016e59f95a49#a983f4383fb1ad8c1c66acb1d5b0016e59f95a49"
|
||||
source = "git+https://github.com/RustPython/Parser.git?rev=718354673eb2cc9645d63fc0c50b4ad08e5595c2#718354673eb2cc9645d63fc0c50b4ad08e5595c2"
|
||||
dependencies = [
|
||||
"bitflags 2.2.1",
|
||||
"itertools",
|
||||
|
@ -2094,7 +2105,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "rustpython-literal"
|
||||
version = "0.2.0"
|
||||
source = "git+https://github.com/RustPython/Parser.git?rev=a983f4383fb1ad8c1c66acb1d5b0016e59f95a49#a983f4383fb1ad8c1c66acb1d5b0016e59f95a49"
|
||||
source = "git+https://github.com/RustPython/Parser.git?rev=718354673eb2cc9645d63fc0c50b4ad08e5595c2#718354673eb2cc9645d63fc0c50b4ad08e5595c2"
|
||||
dependencies = [
|
||||
"hexf-parse",
|
||||
"lexical-parse-float",
|
||||
|
@ -2105,7 +2116,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "rustpython-parser"
|
||||
version = "0.2.0"
|
||||
source = "git+https://github.com/RustPython/Parser.git?rev=a983f4383fb1ad8c1c66acb1d5b0016e59f95a49#a983f4383fb1ad8c1c66acb1d5b0016e59f95a49"
|
||||
source = "git+https://github.com/RustPython/Parser.git?rev=718354673eb2cc9645d63fc0c50b4ad08e5595c2#718354673eb2cc9645d63fc0c50b4ad08e5595c2"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"itertools",
|
||||
|
@ -2127,8 +2138,9 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "rustpython-parser-core"
|
||||
version = "0.2.0"
|
||||
source = "git+https://github.com/RustPython/Parser.git?rev=a983f4383fb1ad8c1c66acb1d5b0016e59f95a49#a983f4383fb1ad8c1c66acb1d5b0016e59f95a49"
|
||||
source = "git+https://github.com/RustPython/Parser.git?rev=718354673eb2cc9645d63fc0c50b4ad08e5595c2#718354673eb2cc9645d63fc0c50b4ad08e5595c2"
|
||||
dependencies = [
|
||||
"ruff_source_location",
|
||||
"ruff_text_size",
|
||||
]
|
||||
|
||||
|
|
|
@ -31,10 +31,10 @@ proc-macro2 = { version = "1.0.51" }
|
|||
quote = { version = "1.0.23" }
|
||||
regex = { version = "1.7.1" }
|
||||
rustc-hash = { version = "1.1.0" }
|
||||
ruff_text_size = { git = "https://github.com/RustPython/Parser.git", rev = "a983f4383fb1ad8c1c66acb1d5b0016e59f95a49" }
|
||||
rustpython-format = { git = "https://github.com/RustPython/Parser.git", rev = "a983f4383fb1ad8c1c66acb1d5b0016e59f95a49" }
|
||||
rustpython-literal = { git = "https://github.com/RustPython/Parser.git", rev = "a983f4383fb1ad8c1c66acb1d5b0016e59f95a49" }
|
||||
rustpython-parser = { git = "https://github.com/RustPython/Parser.git", rev = "a983f4383fb1ad8c1c66acb1d5b0016e59f95a49" , default-features = false}
|
||||
ruff_text_size = { git = "https://github.com/RustPython/Parser.git", rev = "718354673eb2cc9645d63fc0c50b4ad08e5595c2" }
|
||||
rustpython-format = { git = "https://github.com/RustPython/Parser.git", rev = "718354673eb2cc9645d63fc0c50b4ad08e5595c2" }
|
||||
rustpython-literal = { git = "https://github.com/RustPython/Parser.git", rev = "718354673eb2cc9645d63fc0c50b4ad08e5595c2" }
|
||||
rustpython-parser = { git = "https://github.com/RustPython/Parser.git", rev = "718354673eb2cc9645d63fc0c50b4ad08e5595c2" , features = ["all-nodes-with-ranges"]}
|
||||
schemars = { version = "0.8.12" }
|
||||
serde = { version = "1.0.152", features = ["derive"] }
|
||||
serde_json = { version = "1.0.93", features = ["preserve_order"] }
|
||||
|
|
|
@ -5,7 +5,7 @@ use libcst_native::{
|
|||
Codegen, CodegenState, ImportNames, ParenthesizableWhitespace, SmallStatement, Statement,
|
||||
};
|
||||
use ruff_text_size::{TextLen, TextRange, TextSize};
|
||||
use rustpython_parser::ast::{self, ExcepthandlerKind, Expr, Keyword, Stmt, StmtKind};
|
||||
use rustpython_parser::ast::{self, Excepthandler, Expr, Keyword, Ranged, Stmt};
|
||||
use rustpython_parser::{lexer, Mode, Tok};
|
||||
|
||||
use ruff_diagnostics::Edit;
|
||||
|
@ -27,22 +27,22 @@ fn has_single_child(body: &[Stmt], deleted: &[&Stmt]) -> bool {
|
|||
|
||||
/// Determine if a child is the only statement in its body.
|
||||
fn is_lone_child(child: &Stmt, parent: &Stmt, deleted: &[&Stmt]) -> Result<bool> {
|
||||
match &parent.node {
|
||||
StmtKind::FunctionDef(ast::StmtFunctionDef { body, .. })
|
||||
| StmtKind::AsyncFunctionDef(ast::StmtAsyncFunctionDef { body, .. })
|
||||
| StmtKind::ClassDef(ast::StmtClassDef { body, .. })
|
||||
| StmtKind::With(ast::StmtWith { body, .. })
|
||||
| StmtKind::AsyncWith(ast::StmtAsyncWith { body, .. }) => {
|
||||
match parent {
|
||||
Stmt::FunctionDef(ast::StmtFunctionDef { body, .. })
|
||||
| Stmt::AsyncFunctionDef(ast::StmtAsyncFunctionDef { body, .. })
|
||||
| Stmt::ClassDef(ast::StmtClassDef { body, .. })
|
||||
| Stmt::With(ast::StmtWith { body, .. })
|
||||
| Stmt::AsyncWith(ast::StmtAsyncWith { body, .. }) => {
|
||||
if body.iter().contains(child) {
|
||||
Ok(has_single_child(body, deleted))
|
||||
} else {
|
||||
bail!("Unable to find child in parent body")
|
||||
}
|
||||
}
|
||||
StmtKind::For(ast::StmtFor { body, orelse, .. })
|
||||
| StmtKind::AsyncFor(ast::StmtAsyncFor { body, orelse, .. })
|
||||
| StmtKind::While(ast::StmtWhile { body, orelse, .. })
|
||||
| StmtKind::If(ast::StmtIf { body, orelse, .. }) => {
|
||||
Stmt::For(ast::StmtFor { body, orelse, .. })
|
||||
| Stmt::AsyncFor(ast::StmtAsyncFor { body, orelse, .. })
|
||||
| Stmt::While(ast::StmtWhile { body, orelse, .. })
|
||||
| Stmt::If(ast::StmtIf { body, orelse, .. }) => {
|
||||
if body.iter().contains(child) {
|
||||
Ok(has_single_child(body, deleted))
|
||||
} else if orelse.iter().contains(child) {
|
||||
|
@ -51,17 +51,19 @@ fn is_lone_child(child: &Stmt, parent: &Stmt, deleted: &[&Stmt]) -> Result<bool>
|
|||
bail!("Unable to find child in parent body")
|
||||
}
|
||||
}
|
||||
StmtKind::Try(ast::StmtTry {
|
||||
Stmt::Try(ast::StmtTry {
|
||||
body,
|
||||
handlers,
|
||||
orelse,
|
||||
finalbody,
|
||||
range: _,
|
||||
})
|
||||
| StmtKind::TryStar(ast::StmtTryStar {
|
||||
| Stmt::TryStar(ast::StmtTryStar {
|
||||
body,
|
||||
handlers,
|
||||
orelse,
|
||||
finalbody,
|
||||
range: _,
|
||||
}) => {
|
||||
if body.iter().contains(child) {
|
||||
Ok(has_single_child(body, deleted))
|
||||
|
@ -69,10 +71,8 @@ fn is_lone_child(child: &Stmt, parent: &Stmt, deleted: &[&Stmt]) -> Result<bool>
|
|||
Ok(has_single_child(orelse, deleted))
|
||||
} else if finalbody.iter().contains(child) {
|
||||
Ok(has_single_child(finalbody, deleted))
|
||||
} else if let Some(body) = handlers.iter().find_map(|handler| match &handler.node {
|
||||
ExcepthandlerKind::ExceptHandler(ast::ExcepthandlerExceptHandler {
|
||||
body, ..
|
||||
}) => {
|
||||
} else if let Some(body) = handlers.iter().find_map(|handler| match handler {
|
||||
Excepthandler::ExceptHandler(ast::ExcepthandlerExceptHandler { body, .. }) => {
|
||||
if body.iter().contains(child) {
|
||||
Some(body)
|
||||
} else {
|
||||
|
@ -85,7 +85,7 @@ fn is_lone_child(child: &Stmt, parent: &Stmt, deleted: &[&Stmt]) -> Result<bool>
|
|||
bail!("Unable to find child in parent body")
|
||||
}
|
||||
}
|
||||
StmtKind::Match(ast::StmtMatch { cases, .. }) => {
|
||||
Stmt::Match(ast::StmtMatch { cases, .. }) => {
|
||||
if let Some(body) = cases.iter().find_map(|case| {
|
||||
if case.body.iter().contains(child) {
|
||||
Some(&case.body)
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -2,7 +2,7 @@
|
|||
use std::borrow::Cow;
|
||||
use std::path::Path;
|
||||
|
||||
use rustpython_parser::ast::{self, StmtKind, Suite};
|
||||
use rustpython_parser::ast::{self, Ranged, Stmt, Suite};
|
||||
|
||||
use ruff_diagnostics::Diagnostic;
|
||||
use ruff_python_ast::helpers::to_module_path;
|
||||
|
@ -28,18 +28,19 @@ fn extract_import_map(path: &Path, package: Option<&Path>, blocks: &[&Block]) ->
|
|||
let num_imports = blocks.iter().map(|block| block.imports.len()).sum();
|
||||
let mut module_imports = Vec::with_capacity(num_imports);
|
||||
for stmt in blocks.iter().flat_map(|block| &block.imports) {
|
||||
match &stmt.node {
|
||||
StmtKind::Import(ast::StmtImport { names }) => {
|
||||
match stmt {
|
||||
Stmt::Import(ast::StmtImport { names, range: _ }) => {
|
||||
module_imports.extend(
|
||||
names
|
||||
.iter()
|
||||
.map(|name| ModuleImport::new(name.node.name.to_string(), stmt.range())),
|
||||
.map(|name| ModuleImport::new(name.name.to_string(), stmt.range())),
|
||||
);
|
||||
}
|
||||
StmtKind::ImportFrom(ast::StmtImportFrom {
|
||||
Stmt::ImportFrom(ast::StmtImportFrom {
|
||||
module,
|
||||
names,
|
||||
level,
|
||||
range: _,
|
||||
}) => {
|
||||
let level = level.map_or(0, |level| level.to_usize());
|
||||
let module = if let Some(module) = module {
|
||||
|
@ -60,10 +61,10 @@ fn extract_import_map(path: &Path, package: Option<&Path>, blocks: &[&Block]) ->
|
|||
Cow::Owned(module_path[..module_path.len() - level].join("."))
|
||||
};
|
||||
module_imports.extend(names.iter().map(|name| {
|
||||
ModuleImport::new(format!("{}.{}", module, name.node.name), name.range())
|
||||
ModuleImport::new(format!("{}.{}", module, name.name), name.range())
|
||||
}));
|
||||
}
|
||||
_ => panic!("Expected StmtKind::Import | StmtKind::ImportFrom"),
|
||||
_ => panic!("Expected Stmt::Import | Stmt::ImportFrom"),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use libcst_native::{Expression, NameOrAttribute};
|
||||
|
||||
fn compose_call_path_inner<'a>(expr: &'a Expression, parts: &mut Vec<&'a str>) {
|
||||
match &expr {
|
||||
match expr {
|
||||
Expression::Call(expr) => {
|
||||
compose_call_path_inner(&expr.func, parts);
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
use std::iter::FusedIterator;
|
||||
|
||||
use ruff_text_size::{TextRange, TextSize};
|
||||
use rustpython_parser::ast::{self, Constant, ExprKind, Stmt, StmtKind, Suite};
|
||||
use rustpython_parser::ast::{self, Constant, Expr, Ranged, Stmt, Suite};
|
||||
use rustpython_parser::lexer::LexResult;
|
||||
use rustpython_parser::Tok;
|
||||
|
||||
|
@ -79,11 +79,11 @@ struct StringLinesVisitor<'a> {
|
|||
|
||||
impl StatementVisitor<'_> for StringLinesVisitor<'_> {
|
||||
fn visit_stmt(&mut self, stmt: &Stmt) {
|
||||
if let StmtKind::Expr(ast::StmtExpr { value }) = &stmt.node {
|
||||
if let ExprKind::Constant(ast::ExprConstant {
|
||||
if let Stmt::Expr(ast::StmtExpr { value, range: _ }) = stmt {
|
||||
if let Expr::Constant(ast::ExprConstant {
|
||||
value: Constant::Str(..),
|
||||
..
|
||||
}) = &value.node
|
||||
}) = value.as_ref()
|
||||
{
|
||||
for line in UniversalNewlineIterator::with_offset(
|
||||
self.locator.slice(value.range()),
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
//! Extract docstrings from an AST.
|
||||
|
||||
use rustpython_parser::ast::{self, Constant, Expr, ExprKind, Stmt, StmtKind};
|
||||
use rustpython_parser::ast::{self, Constant, Expr, Stmt};
|
||||
|
||||
use ruff_python_semantic::definition::{Definition, DefinitionId, Definitions, Member, MemberKind};
|
||||
|
||||
|
@ -8,13 +8,13 @@ use ruff_python_semantic::definition::{Definition, DefinitionId, Definitions, Me
|
|||
pub(crate) fn docstring_from(suite: &[Stmt]) -> Option<&Expr> {
|
||||
let stmt = suite.first()?;
|
||||
// Require the docstring to be a standalone expression.
|
||||
let StmtKind::Expr(ast::StmtExpr { value }) = &stmt.node else {
|
||||
let Stmt::Expr(ast::StmtExpr { value, range: _ }) = stmt else {
|
||||
return None;
|
||||
};
|
||||
// Only match strings.
|
||||
if !matches!(
|
||||
&value.node,
|
||||
ExprKind::Constant(ast::ExprConstant {
|
||||
value.as_ref(),
|
||||
Expr::Constant(ast::ExprConstant {
|
||||
value: Constant::Str(_),
|
||||
..
|
||||
})
|
||||
|
@ -29,10 +29,9 @@ pub(crate) fn extract_docstring<'a>(definition: &'a Definition<'a>) -> Option<&'
|
|||
match definition {
|
||||
Definition::Module(module) => docstring_from(module.python_ast),
|
||||
Definition::Member(member) => {
|
||||
if let StmtKind::ClassDef(ast::StmtClassDef { body, .. })
|
||||
| StmtKind::FunctionDef(ast::StmtFunctionDef { body, .. })
|
||||
| StmtKind::AsyncFunctionDef(ast::StmtAsyncFunctionDef { body, .. }) =
|
||||
&member.stmt.node
|
||||
if let Stmt::ClassDef(ast::StmtClassDef { body, .. })
|
||||
| Stmt::FunctionDef(ast::StmtFunctionDef { body, .. })
|
||||
| Stmt::AsyncFunctionDef(ast::StmtAsyncFunctionDef { body, .. }) = &member.stmt
|
||||
{
|
||||
docstring_from(body)
|
||||
} else {
|
||||
|
|
|
@ -2,7 +2,7 @@ use std::fmt::{Debug, Formatter};
|
|||
use std::ops::Deref;
|
||||
|
||||
use ruff_text_size::{TextRange, TextSize};
|
||||
use rustpython_parser::ast::Expr;
|
||||
use rustpython_parser::ast::{Expr, Ranged};
|
||||
|
||||
use ruff_python_semantic::definition::Definition;
|
||||
|
||||
|
@ -29,15 +29,15 @@ impl<'a> Docstring<'a> {
|
|||
DocstringBody { docstring: self }
|
||||
}
|
||||
|
||||
pub(crate) const fn start(&self) -> TextSize {
|
||||
pub(crate) fn start(&self) -> TextSize {
|
||||
self.expr.start()
|
||||
}
|
||||
|
||||
pub(crate) const fn end(&self) -> TextSize {
|
||||
pub(crate) fn end(&self) -> TextSize {
|
||||
self.expr.end()
|
||||
}
|
||||
|
||||
pub(crate) const fn range(&self) -> TextRange {
|
||||
pub(crate) fn range(&self) -> TextRange {
|
||||
self.expr.range()
|
||||
}
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
use anyhow::Result;
|
||||
use libcst_native::{Codegen, CodegenState, ImportAlias, Name, NameOrAttribute};
|
||||
use ruff_text_size::TextSize;
|
||||
use rustpython_parser::ast::{self, Stmt, StmtKind, Suite};
|
||||
use rustpython_parser::ast::{self, Ranged, Stmt, Suite};
|
||||
use rustpython_parser::{lexer, Mode, Tok};
|
||||
|
||||
use ruff_diagnostics::Edit;
|
||||
|
@ -71,7 +71,7 @@ impl<'a> Importer<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Return the top-level [`Stmt`] that imports the given module using `StmtKind::ImportFrom`
|
||||
/// Return the top-level [`Stmt`] that imports the given module using `Stmt::ImportFrom`
|
||||
/// preceding the given position, if any.
|
||||
pub fn find_import_from(&self, module: &str, at: TextSize) -> Option<&Stmt> {
|
||||
let mut import_from = None;
|
||||
|
@ -79,11 +79,11 @@ impl<'a> Importer<'a> {
|
|||
if stmt.start() >= at {
|
||||
break;
|
||||
}
|
||||
if let StmtKind::ImportFrom(ast::StmtImportFrom {
|
||||
if let Stmt::ImportFrom(ast::StmtImportFrom {
|
||||
module: name,
|
||||
level,
|
||||
..
|
||||
}) = &stmt.node
|
||||
}) = stmt
|
||||
{
|
||||
if level.map_or(true, |level| level.to_u32() == 0)
|
||||
&& name.as_ref().map_or(false, |name| name == module)
|
||||
|
@ -95,7 +95,7 @@ impl<'a> Importer<'a> {
|
|||
import_from
|
||||
}
|
||||
|
||||
/// Add the given member to an existing `StmtKind::ImportFrom` statement.
|
||||
/// Add the given member to an existing `Stmt::ImportFrom` statement.
|
||||
pub fn add_member(&self, stmt: &Stmt, member: &str) -> Result<Edit> {
|
||||
let mut tree = match_module(self.locator.slice(stmt.range()))?;
|
||||
let import_from = match_import_from(&mut tree)?;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use num_bigint::BigInt;
|
||||
use rustpython_parser::ast::{self, Attributed, Cmpop, Constant, Expr, ExprKind};
|
||||
use rustpython_parser::ast::{self, Cmpop, Constant, Expr, Ranged};
|
||||
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
|
@ -123,16 +123,17 @@ fn is_sys(checker: &Checker, expr: &Expr, target: &str) -> bool {
|
|||
/// YTT101, YTT102, YTT301, YTT303
|
||||
pub(crate) fn subscript(checker: &mut Checker, value: &Expr, slice: &Expr) {
|
||||
if is_sys(checker, value, "version") {
|
||||
match &slice.node {
|
||||
ExprKind::Slice(ast::ExprSlice {
|
||||
match slice {
|
||||
Expr::Slice(ast::ExprSlice {
|
||||
lower: None,
|
||||
upper: Some(upper),
|
||||
step: None,
|
||||
range: _,
|
||||
}) => {
|
||||
if let ExprKind::Constant(ast::ExprConstant {
|
||||
if let Expr::Constant(ast::ExprConstant {
|
||||
value: Constant::Int(i),
|
||||
..
|
||||
}) = &upper.node
|
||||
}) = upper.as_ref()
|
||||
{
|
||||
if *i == BigInt::from(1)
|
||||
&& checker.settings.rules.enabled(Rule::SysVersionSlice1)
|
||||
|
@ -150,7 +151,7 @@ pub(crate) fn subscript(checker: &mut Checker, value: &Expr, slice: &Expr) {
|
|||
}
|
||||
}
|
||||
|
||||
ExprKind::Constant(ast::ExprConstant {
|
||||
Expr::Constant(ast::ExprConstant {
|
||||
value: Constant::Int(i),
|
||||
..
|
||||
}) => {
|
||||
|
@ -173,26 +174,22 @@ pub(crate) fn subscript(checker: &mut Checker, value: &Expr, slice: &Expr) {
|
|||
|
||||
/// YTT103, YTT201, YTT203, YTT204, YTT302
|
||||
pub(crate) fn compare(checker: &mut Checker, left: &Expr, ops: &[Cmpop], comparators: &[Expr]) {
|
||||
match &left.node {
|
||||
ExprKind::Subscript(ast::ExprSubscript { value, slice, .. })
|
||||
match left {
|
||||
Expr::Subscript(ast::ExprSubscript { value, slice, .. })
|
||||
if is_sys(checker, value, "version_info") =>
|
||||
{
|
||||
if let ExprKind::Constant(ast::ExprConstant {
|
||||
if let Expr::Constant(ast::ExprConstant {
|
||||
value: Constant::Int(i),
|
||||
..
|
||||
}) = &slice.node
|
||||
}) = slice.as_ref()
|
||||
{
|
||||
if *i == BigInt::from(0) {
|
||||
if let (
|
||||
[Cmpop::Eq | Cmpop::NotEq],
|
||||
[Attributed {
|
||||
node:
|
||||
ExprKind::Constant(ast::ExprConstant {
|
||||
[Expr::Constant(ast::ExprConstant {
|
||||
value: Constant::Int(n),
|
||||
..
|
||||
}),
|
||||
..
|
||||
}],
|
||||
})],
|
||||
) = (ops, comparators)
|
||||
{
|
||||
if *n == BigInt::from(3)
|
||||
|
@ -206,14 +203,10 @@ pub(crate) fn compare(checker: &mut Checker, left: &Expr, ops: &[Cmpop], compara
|
|||
} else if *i == BigInt::from(1) {
|
||||
if let (
|
||||
[Cmpop::Lt | Cmpop::LtE | Cmpop::Gt | Cmpop::GtE],
|
||||
[Attributed {
|
||||
node:
|
||||
ExprKind::Constant(ast::ExprConstant {
|
||||
[Expr::Constant(ast::ExprConstant {
|
||||
value: Constant::Int(_),
|
||||
..
|
||||
}),
|
||||
..
|
||||
}],
|
||||
})],
|
||||
) = (ops, comparators)
|
||||
{
|
||||
if checker.settings.rules.enabled(Rule::SysVersionInfo1CmpInt) {
|
||||
|
@ -226,19 +219,15 @@ pub(crate) fn compare(checker: &mut Checker, left: &Expr, ops: &[Cmpop], compara
|
|||
}
|
||||
}
|
||||
|
||||
ExprKind::Attribute(ast::ExprAttribute { value, attr, .. })
|
||||
Expr::Attribute(ast::ExprAttribute { value, attr, .. })
|
||||
if is_sys(checker, value, "version_info") && attr == "minor" =>
|
||||
{
|
||||
if let (
|
||||
[Cmpop::Lt | Cmpop::LtE | Cmpop::Gt | Cmpop::GtE],
|
||||
[Attributed {
|
||||
node:
|
||||
ExprKind::Constant(ast::ExprConstant {
|
||||
[Expr::Constant(ast::ExprConstant {
|
||||
value: Constant::Int(_),
|
||||
..
|
||||
}),
|
||||
..
|
||||
}],
|
||||
})],
|
||||
) = (ops, comparators)
|
||||
{
|
||||
if checker
|
||||
|
@ -259,14 +248,10 @@ pub(crate) fn compare(checker: &mut Checker, left: &Expr, ops: &[Cmpop], compara
|
|||
if is_sys(checker, left, "version") {
|
||||
if let (
|
||||
[Cmpop::Lt | Cmpop::LtE | Cmpop::Gt | Cmpop::GtE],
|
||||
[Attributed {
|
||||
node:
|
||||
ExprKind::Constant(ast::ExprConstant {
|
||||
[Expr::Constant(ast::ExprConstant {
|
||||
value: Constant::Str(s),
|
||||
..
|
||||
}),
|
||||
..
|
||||
}],
|
||||
})],
|
||||
) = (ops, comparators)
|
||||
{
|
||||
if s.len() == 1 {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use anyhow::{bail, Result};
|
||||
use rustpython_parser::ast::Stmt;
|
||||
use rustpython_parser::ast::{Ranged, Stmt};
|
||||
use rustpython_parser::{lexer, Mode, Tok};
|
||||
|
||||
use ruff_diagnostics::Edit;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use rustpython_parser::ast::{self, Arguments, Expr, Stmt, StmtKind};
|
||||
use rustpython_parser::ast::{self, Arguments, Expr, Stmt};
|
||||
|
||||
use ruff_python_ast::cast;
|
||||
use ruff_python_semantic::analyze::visibility;
|
||||
|
@ -8,9 +8,9 @@ use crate::checkers::ast::Checker;
|
|||
|
||||
pub(super) fn match_function_def(
|
||||
stmt: &Stmt,
|
||||
) -> (&str, &Arguments, Option<&Expr>, &Vec<Stmt>, &Vec<Expr>) {
|
||||
match &stmt.node {
|
||||
StmtKind::FunctionDef(ast::StmtFunctionDef {
|
||||
) -> (&str, &Arguments, Option<&Expr>, &[Stmt], &[Expr]) {
|
||||
match stmt {
|
||||
Stmt::FunctionDef(ast::StmtFunctionDef {
|
||||
name,
|
||||
args,
|
||||
returns,
|
||||
|
@ -18,7 +18,7 @@ pub(super) fn match_function_def(
|
|||
decorator_list,
|
||||
..
|
||||
})
|
||||
| StmtKind::AsyncFunctionDef(ast::StmtAsyncFunctionDef {
|
||||
| Stmt::AsyncFunctionDef(ast::StmtAsyncFunctionDef {
|
||||
name,
|
||||
args,
|
||||
returns,
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use rustpython_parser::ast::{Expr, ExprKind, Stmt};
|
||||
use rustpython_parser::ast::{Expr, Ranged, Stmt};
|
||||
|
||||
use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
|
@ -419,8 +419,8 @@ fn is_none_returning(body: &[Stmt]) -> bool {
|
|||
visitor.visit_body(body);
|
||||
for expr in visitor.returns.into_iter().flatten() {
|
||||
if !matches!(
|
||||
expr.node,
|
||||
ExprKind::Constant(ref constant) if constant.value.is_none()
|
||||
expr,
|
||||
Expr::Constant(ref constant) if constant.value.is_none()
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
@ -495,20 +495,20 @@ pub(crate) fn definition(
|
|||
)
|
||||
{
|
||||
// ANN401 for dynamically typed arguments
|
||||
if let Some(annotation) = &arg.node.annotation {
|
||||
if let Some(annotation) = &arg.annotation {
|
||||
has_any_typed_arg = true;
|
||||
if checker.settings.rules.enabled(Rule::AnyType) {
|
||||
check_dynamically_typed(
|
||||
checker,
|
||||
annotation,
|
||||
|| arg.node.arg.to_string(),
|
||||
|| arg.arg.to_string(),
|
||||
&mut diagnostics,
|
||||
is_overridden,
|
||||
);
|
||||
}
|
||||
} else {
|
||||
if !(checker.settings.flake8_annotations.suppress_dummy_args
|
||||
&& checker.settings.dummy_variable_rgx.is_match(&arg.node.arg))
|
||||
&& checker.settings.dummy_variable_rgx.is_match(&arg.arg))
|
||||
{
|
||||
if checker
|
||||
.settings
|
||||
|
@ -517,7 +517,7 @@ pub(crate) fn definition(
|
|||
{
|
||||
diagnostics.push(Diagnostic::new(
|
||||
MissingTypeFunctionArgument {
|
||||
name: arg.node.arg.to_string(),
|
||||
name: arg.arg.to_string(),
|
||||
},
|
||||
arg.range(),
|
||||
));
|
||||
|
@ -528,11 +528,11 @@ pub(crate) fn definition(
|
|||
|
||||
// ANN002, ANN401
|
||||
if let Some(arg) = &args.vararg {
|
||||
if let Some(expr) = &arg.node.annotation {
|
||||
if let Some(expr) = &arg.annotation {
|
||||
has_any_typed_arg = true;
|
||||
if !checker.settings.flake8_annotations.allow_star_arg_any {
|
||||
if checker.settings.rules.enabled(Rule::AnyType) {
|
||||
let name = &arg.node.arg;
|
||||
let name = &arg.arg;
|
||||
check_dynamically_typed(
|
||||
checker,
|
||||
expr,
|
||||
|
@ -544,12 +544,12 @@ pub(crate) fn definition(
|
|||
}
|
||||
} else {
|
||||
if !(checker.settings.flake8_annotations.suppress_dummy_args
|
||||
&& checker.settings.dummy_variable_rgx.is_match(&arg.node.arg))
|
||||
&& checker.settings.dummy_variable_rgx.is_match(&arg.arg))
|
||||
{
|
||||
if checker.settings.rules.enabled(Rule::MissingTypeArgs) {
|
||||
diagnostics.push(Diagnostic::new(
|
||||
MissingTypeArgs {
|
||||
name: arg.node.arg.to_string(),
|
||||
name: arg.arg.to_string(),
|
||||
},
|
||||
arg.range(),
|
||||
));
|
||||
|
@ -560,11 +560,11 @@ pub(crate) fn definition(
|
|||
|
||||
// ANN003, ANN401
|
||||
if let Some(arg) = &args.kwarg {
|
||||
if let Some(expr) = &arg.node.annotation {
|
||||
if let Some(expr) = &arg.annotation {
|
||||
has_any_typed_arg = true;
|
||||
if !checker.settings.flake8_annotations.allow_star_arg_any {
|
||||
if checker.settings.rules.enabled(Rule::AnyType) {
|
||||
let name = &arg.node.arg;
|
||||
let name = &arg.arg;
|
||||
check_dynamically_typed(
|
||||
checker,
|
||||
expr,
|
||||
|
@ -576,12 +576,12 @@ pub(crate) fn definition(
|
|||
}
|
||||
} else {
|
||||
if !(checker.settings.flake8_annotations.suppress_dummy_args
|
||||
&& checker.settings.dummy_variable_rgx.is_match(&arg.node.arg))
|
||||
&& checker.settings.dummy_variable_rgx.is_match(&arg.arg))
|
||||
{
|
||||
if checker.settings.rules.enabled(Rule::MissingTypeKwargs) {
|
||||
diagnostics.push(Diagnostic::new(
|
||||
MissingTypeKwargs {
|
||||
name: arg.node.arg.to_string(),
|
||||
name: arg.arg.to_string(),
|
||||
},
|
||||
arg.range(),
|
||||
));
|
||||
|
@ -593,12 +593,12 @@ pub(crate) fn definition(
|
|||
// ANN101, ANN102
|
||||
if is_method && !visibility::is_staticmethod(&checker.ctx, cast::decorator_list(stmt)) {
|
||||
if let Some(arg) = args.posonlyargs.first().or_else(|| args.args.first()) {
|
||||
if arg.node.annotation.is_none() {
|
||||
if arg.annotation.is_none() {
|
||||
if visibility::is_classmethod(&checker.ctx, cast::decorator_list(stmt)) {
|
||||
if checker.settings.rules.enabled(Rule::MissingTypeCls) {
|
||||
diagnostics.push(Diagnostic::new(
|
||||
MissingTypeCls {
|
||||
name: arg.node.arg.to_string(),
|
||||
name: arg.arg.to_string(),
|
||||
},
|
||||
arg.range(),
|
||||
));
|
||||
|
@ -607,7 +607,7 @@ pub(crate) fn definition(
|
|||
if checker.settings.rules.enabled(Rule::MissingTypeSelf) {
|
||||
diagnostics.push(Diagnostic::new(
|
||||
MissingTypeSelf {
|
||||
name: arg.node.arg.to_string(),
|
||||
name: arg.arg.to_string(),
|
||||
},
|
||||
arg.range(),
|
||||
));
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use rustpython_parser::ast;
|
||||
use rustpython_parser::ast::{Expr, ExprKind};
|
||||
use rustpython_parser::ast::{Expr, Ranged};
|
||||
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
|
@ -67,12 +67,13 @@ const BLOCKING_HTTP_CALLS: &[&[&str]] = &[
|
|||
/// ASYNC100
|
||||
pub(crate) fn blocking_http_call(checker: &mut Checker, expr: &Expr) {
|
||||
if in_async_function(&checker.ctx) {
|
||||
if let ExprKind::Call(ast::ExprCall { func, .. }) = &expr.node {
|
||||
if let Expr::Call(ast::ExprCall { func, .. }) = expr {
|
||||
if let Some(call_path) = checker.ctx.resolve_call_path(func) {
|
||||
if BLOCKING_HTTP_CALLS.contains(&call_path.as_slice()) {
|
||||
checker
|
||||
.diagnostics
|
||||
.push(Diagnostic::new(BlockingHttpCallInAsyncFunction, func.range));
|
||||
checker.diagnostics.push(Diagnostic::new(
|
||||
BlockingHttpCallInAsyncFunction,
|
||||
func.range(),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -133,12 +134,12 @@ const OPEN_SLEEP_OR_SUBPROCESS_CALL: &[&[&str]] = &[
|
|||
/// ASYNC101
|
||||
pub(crate) fn open_sleep_or_subprocess_call(checker: &mut Checker, expr: &Expr) {
|
||||
if in_async_function(&checker.ctx) {
|
||||
if let ExprKind::Call(ast::ExprCall { func, .. }) = &expr.node {
|
||||
if let Expr::Call(ast::ExprCall { func, .. }) = expr {
|
||||
if let Some(call_path) = checker.ctx.resolve_call_path(func) {
|
||||
if OPEN_SLEEP_OR_SUBPROCESS_CALL.contains(&call_path.as_slice()) {
|
||||
checker.diagnostics.push(Diagnostic::new(
|
||||
OpenSleepOrSubprocessInAsyncFunction,
|
||||
func.range,
|
||||
func.range(),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
@ -197,12 +198,12 @@ const UNSAFE_OS_METHODS: &[&[&str]] = &[
|
|||
/// ASYNC102
|
||||
pub(crate) fn blocking_os_call(checker: &mut Checker, expr: &Expr) {
|
||||
if in_async_function(&checker.ctx) {
|
||||
if let ExprKind::Call(ast::ExprCall { func, .. }) = &expr.node {
|
||||
if let Expr::Call(ast::ExprCall { func, .. }) = expr {
|
||||
if let Some(call_path) = checker.ctx.resolve_call_path(func) {
|
||||
if UNSAFE_OS_METHODS.contains(&call_path.as_slice()) {
|
||||
checker
|
||||
.diagnostics
|
||||
.push(Diagnostic::new(BlockingOsCallInAsyncFunction, func.range));
|
||||
.push(Diagnostic::new(BlockingOsCallInAsyncFunction, func.range()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use once_cell::sync::Lazy;
|
||||
use regex::Regex;
|
||||
use rustpython_parser::ast::{self, Constant, Expr, ExprKind};
|
||||
use rustpython_parser::ast::{self, Constant, Expr};
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
|
||||
|
@ -9,8 +9,8 @@ static PASSWORD_CANDIDATE_REGEX: Lazy<Regex> = Lazy::new(|| {
|
|||
});
|
||||
|
||||
pub(crate) fn string_literal(expr: &Expr) -> Option<&str> {
|
||||
match &expr.node {
|
||||
ExprKind::Constant(ast::ExprConstant {
|
||||
match expr {
|
||||
Expr::Constant(ast::ExprConstant {
|
||||
value: Constant::Str(string),
|
||||
..
|
||||
}) => Some(string),
|
||||
|
@ -24,7 +24,7 @@ pub(crate) fn matches_password_name(string: &str) -> bool {
|
|||
|
||||
pub(crate) fn is_untyped_exception(type_: Option<&Expr>, checker: &Checker) -> bool {
|
||||
type_.map_or(true, |type_| {
|
||||
if let ExprKind::Tuple(ast::ExprTuple { elts, .. }) = &type_.node {
|
||||
if let Expr::Tuple(ast::ExprTuple { elts, .. }) = &type_ {
|
||||
elts.iter().any(|type_| {
|
||||
checker
|
||||
.ctx
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use ruff_text_size::{TextLen, TextRange};
|
||||
use rustpython_parser::ast::Stmt;
|
||||
use rustpython_parser::ast::{Ranged, Stmt};
|
||||
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use num_traits::ToPrimitive;
|
||||
use once_cell::sync::Lazy;
|
||||
use rustc_hash::FxHashMap;
|
||||
use rustpython_parser::ast::{self, Constant, Expr, ExprKind, Keyword, Operator};
|
||||
use rustpython_parser::ast::{self, Constant, Expr, Keyword, Operator, Ranged};
|
||||
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
|
@ -69,15 +69,20 @@ static PYSTAT_MAPPING: Lazy<FxHashMap<&'static str, u16>> = Lazy::new(|| {
|
|||
});
|
||||
|
||||
fn get_int_value(expr: &Expr) -> Option<u16> {
|
||||
match &expr.node {
|
||||
ExprKind::Constant(ast::ExprConstant {
|
||||
match expr {
|
||||
Expr::Constant(ast::ExprConstant {
|
||||
value: Constant::Int(value),
|
||||
..
|
||||
}) => value.to_u16(),
|
||||
ExprKind::Attribute(_) => {
|
||||
Expr::Attribute(_) => {
|
||||
compose_call_path(expr).and_then(|path| PYSTAT_MAPPING.get(path.as_str()).copied())
|
||||
}
|
||||
ExprKind::BinOp(ast::ExprBinOp { left, op, right }) => {
|
||||
Expr::BinOp(ast::ExprBinOp {
|
||||
left,
|
||||
op,
|
||||
right,
|
||||
range: _,
|
||||
}) => {
|
||||
if let (Some(left_value), Some(right_value)) =
|
||||
(get_int_value(left), get_int_value(right))
|
||||
{
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use rustpython_parser::ast::{self, Expr, ExprKind};
|
||||
use rustpython_parser::ast::{self, Expr, Ranged};
|
||||
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
|
@ -15,7 +15,7 @@ impl Violation for ExecBuiltin {
|
|||
|
||||
/// S102
|
||||
pub(crate) fn exec_used(expr: &Expr, func: &Expr) -> Option<Diagnostic> {
|
||||
let ExprKind::Name(ast::ExprName { id, .. }) = &func.node else {
|
||||
let Expr::Name(ast::ExprName { id, .. }) = func else {
|
||||
return None;
|
||||
};
|
||||
if id != "exec" {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use rustpython_parser::ast::{Arg, Arguments, Expr};
|
||||
use rustpython_parser::ast::{Arg, Arguments, Expr, Ranged};
|
||||
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
|
@ -23,7 +23,7 @@ impl Violation for HardcodedPasswordDefault {
|
|||
|
||||
fn check_password_kwarg(arg: &Arg, default: &Expr) -> Option<Diagnostic> {
|
||||
string_literal(default).filter(|string| !string.is_empty())?;
|
||||
let kwarg_name = &arg.node.arg;
|
||||
let kwarg_name = &arg.arg;
|
||||
if !matches_password_name(kwarg_name) {
|
||||
return None;
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use rustpython_parser::ast::Keyword;
|
||||
use rustpython_parser::ast::{Keyword, Ranged};
|
||||
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
|
@ -26,8 +26,8 @@ pub(crate) fn hardcoded_password_func_arg(keywords: &[Keyword]) -> Vec<Diagnosti
|
|||
keywords
|
||||
.iter()
|
||||
.filter_map(|keyword| {
|
||||
string_literal(&keyword.node.value).filter(|string| !string.is_empty())?;
|
||||
let arg = keyword.node.arg.as_ref()?;
|
||||
string_literal(&keyword.value).filter(|string| !string.is_empty())?;
|
||||
let arg = keyword.arg.as_ref()?;
|
||||
if !matches_password_name(arg) {
|
||||
return None;
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use rustpython_parser::ast::{self, Constant, Expr, ExprKind};
|
||||
use rustpython_parser::ast::{self, Constant, Expr, Ranged};
|
||||
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
|
@ -22,19 +22,19 @@ impl Violation for HardcodedPasswordString {
|
|||
}
|
||||
|
||||
fn password_target(target: &Expr) -> Option<&str> {
|
||||
let target_name = match &target.node {
|
||||
let target_name = match target {
|
||||
// variable = "s3cr3t"
|
||||
ExprKind::Name(ast::ExprName { id, .. }) => id.as_str(),
|
||||
Expr::Name(ast::ExprName { id, .. }) => id.as_str(),
|
||||
// d["password"] = "s3cr3t"
|
||||
ExprKind::Subscript(ast::ExprSubscript { slice, .. }) => match &slice.node {
|
||||
ExprKind::Constant(ast::ExprConstant {
|
||||
Expr::Subscript(ast::ExprSubscript { slice, .. }) => match slice.as_ref() {
|
||||
Expr::Constant(ast::ExprConstant {
|
||||
value: Constant::Str(string),
|
||||
..
|
||||
}) => string,
|
||||
_ => return None,
|
||||
},
|
||||
// obj.password = "s3cr3t"
|
||||
ExprKind::Attribute(ast::ExprAttribute { attr, .. }) => attr,
|
||||
Expr::Attribute(ast::ExprAttribute { attr, .. }) => attr,
|
||||
_ => return None,
|
||||
};
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use once_cell::sync::Lazy;
|
||||
use regex::Regex;
|
||||
use rustpython_parser::ast::{self, Expr, ExprKind, Operator};
|
||||
use rustpython_parser::ast::{self, Expr, Operator, Ranged};
|
||||
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
|
@ -53,10 +53,10 @@ fn matches_sql_statement(string: &str) -> bool {
|
|||
}
|
||||
|
||||
fn unparse_string_format_expression(checker: &mut Checker, expr: &Expr) -> Option<String> {
|
||||
match &expr.node {
|
||||
match expr {
|
||||
// "select * from table where val = " + "str" + ...
|
||||
// "select * from table where val = %s" % ...
|
||||
ExprKind::BinOp(ast::ExprBinOp {
|
||||
Expr::BinOp(ast::ExprBinOp {
|
||||
op: Operator::Add | Operator::Mod,
|
||||
..
|
||||
}) => {
|
||||
|
@ -67,7 +67,7 @@ fn unparse_string_format_expression(checker: &mut Checker, expr: &Expr) -> Optio
|
|||
return None;
|
||||
};
|
||||
// Only evaluate the full BinOp, not the nested components.
|
||||
let ExprKind::BinOp(_ )= &parent.node else {
|
||||
let Expr::BinOp(_ )= parent else {
|
||||
if any_over_expr(expr, &has_string_literal) {
|
||||
return Some(unparse_expr(expr, checker.stylist));
|
||||
}
|
||||
|
@ -75,8 +75,8 @@ fn unparse_string_format_expression(checker: &mut Checker, expr: &Expr) -> Optio
|
|||
};
|
||||
None
|
||||
}
|
||||
ExprKind::Call(ast::ExprCall { func, .. }) => {
|
||||
let ExprKind::Attribute(ast::ExprAttribute { attr, value, .. }) = &func.node else {
|
||||
Expr::Call(ast::ExprCall { func, .. }) => {
|
||||
let Expr::Attribute(ast::ExprAttribute { attr, value, .. }) = func.as_ref() else {
|
||||
return None;
|
||||
};
|
||||
// "select * from table where val = {}".format(...)
|
||||
|
@ -86,7 +86,7 @@ fn unparse_string_format_expression(checker: &mut Checker, expr: &Expr) -> Optio
|
|||
None
|
||||
}
|
||||
// f"select * from table where val = {val}"
|
||||
ExprKind::JoinedStr(_) => Some(unparse_expr(expr, checker.stylist)),
|
||||
Expr::JoinedStr(_) => Some(unparse_expr(expr, checker.stylist)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use rustpython_parser::ast::Expr;
|
||||
use rustpython_parser::ast::{Expr, Ranged};
|
||||
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use rustpython_parser::ast::{self, Constant, Expr, ExprKind, Keyword};
|
||||
use rustpython_parser::ast::{self, Constant, Expr, Keyword, Ranged};
|
||||
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
|
@ -26,8 +26,8 @@ const WEAK_HASHES: [&str; 4] = ["md4", "md5", "sha", "sha1"];
|
|||
fn is_used_for_security(call_args: &SimpleCallArgs) -> bool {
|
||||
match call_args.keyword_argument("usedforsecurity") {
|
||||
Some(expr) => !matches!(
|
||||
&expr.node,
|
||||
ExprKind::Constant(ast::ExprConstant {
|
||||
expr,
|
||||
Expr::Constant(ast::ExprConstant {
|
||||
value: Constant::Bool(false),
|
||||
..
|
||||
})
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use rustpython_parser::ast::{self, Constant, Expr, ExprKind, Keyword};
|
||||
use rustpython_parser::ast::{self, Constant, Expr, Keyword, Ranged};
|
||||
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
|
@ -46,13 +46,13 @@ pub(crate) fn jinja2_autoescape_false(
|
|||
let call_args = SimpleCallArgs::new(args, keywords);
|
||||
|
||||
if let Some(autoescape_arg) = call_args.keyword_argument("autoescape") {
|
||||
match &autoescape_arg.node {
|
||||
ExprKind::Constant(ast::ExprConstant {
|
||||
match autoescape_arg {
|
||||
Expr::Constant(ast::ExprConstant {
|
||||
value: Constant::Bool(true),
|
||||
..
|
||||
}) => (),
|
||||
ExprKind::Call(ast::ExprCall { func, .. }) => {
|
||||
if let ExprKind::Name(ast::ExprName { id, .. }) = &func.node {
|
||||
Expr::Call(ast::ExprCall { func, .. }) => {
|
||||
if let Expr::Name(ast::ExprName { id, .. }) = func.as_ref() {
|
||||
if id != "select_autoescape" {
|
||||
checker.diagnostics.push(Diagnostic::new(
|
||||
Jinja2AutoescapeFalse { value: true },
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use rustpython_parser::ast::{Expr, Keyword};
|
||||
use rustpython_parser::ast::{Expr, Keyword, Ranged};
|
||||
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use rustpython_parser::ast::{self, Constant, Expr, ExprKind, Keyword};
|
||||
use rustpython_parser::ast::{self, Constant, Expr, Keyword, Ranged};
|
||||
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
|
@ -56,10 +56,10 @@ pub(crate) fn request_with_no_cert_validation(
|
|||
}) {
|
||||
let call_args = SimpleCallArgs::new(args, keywords);
|
||||
if let Some(verify_arg) = call_args.keyword_argument("verify") {
|
||||
if let ExprKind::Constant(ast::ExprConstant {
|
||||
if let Expr::Constant(ast::ExprConstant {
|
||||
value: Constant::Bool(false),
|
||||
..
|
||||
}) = &verify_arg.node
|
||||
}) = &verify_arg
|
||||
{
|
||||
checker.diagnostics.push(Diagnostic::new(
|
||||
RequestWithNoCertValidation {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use rustpython_parser::ast::{self, Constant, Expr, ExprKind, Keyword};
|
||||
use rustpython_parser::ast::{self, Constant, Expr, Keyword, Ranged};
|
||||
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
|
@ -44,8 +44,8 @@ pub(crate) fn request_without_timeout(
|
|||
{
|
||||
let call_args = SimpleCallArgs::new(args, keywords);
|
||||
if let Some(timeout_arg) = call_args.keyword_argument("timeout") {
|
||||
if let Some(timeout) = match &timeout_arg.node {
|
||||
ExprKind::Constant(ast::ExprConstant {
|
||||
if let Some(timeout) = match timeout_arg {
|
||||
Expr::Constant(ast::ExprConstant {
|
||||
value: value @ Constant::None,
|
||||
..
|
||||
}) => Some(unparse_constant(value, checker.stylist)),
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
use once_cell::sync::Lazy;
|
||||
use regex::Regex;
|
||||
use rustpython_parser::ast::{self, Constant, Expr, ExprKind, Keyword};
|
||||
use rustpython_parser::ast::{self, Constant, Expr, Keyword, Ranged};
|
||||
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
|
@ -141,15 +141,9 @@ struct ShellKeyword<'a> {
|
|||
fn find_shell_keyword<'a>(ctx: &Context, keywords: &'a [Keyword]) -> Option<ShellKeyword<'a>> {
|
||||
keywords
|
||||
.iter()
|
||||
.find(|keyword| {
|
||||
keyword
|
||||
.node
|
||||
.arg
|
||||
.as_ref()
|
||||
.map_or(false, |arg| arg == "shell")
|
||||
})
|
||||
.find(|keyword| keyword.arg.as_ref().map_or(false, |arg| arg == "shell"))
|
||||
.map(|keyword| ShellKeyword {
|
||||
truthiness: Truthiness::from_expr(&keyword.node.value, |id| ctx.is_builtin(id)),
|
||||
truthiness: Truthiness::from_expr(&keyword.value, |id| ctx.is_builtin(id)),
|
||||
keyword,
|
||||
})
|
||||
}
|
||||
|
@ -158,8 +152,8 @@ fn find_shell_keyword<'a>(ctx: &Context, keywords: &'a [Keyword]) -> Option<Shel
|
|||
/// definition: string literals are considered okay, but dynamically-computed values are not.
|
||||
fn shell_call_seems_safe(arg: &Expr) -> bool {
|
||||
matches!(
|
||||
arg.node,
|
||||
ExprKind::Constant(ast::ExprConstant {
|
||||
arg,
|
||||
Expr::Constant(ast::ExprConstant {
|
||||
value: Constant::Str(_),
|
||||
..
|
||||
})
|
||||
|
@ -168,8 +162,8 @@ fn shell_call_seems_safe(arg: &Expr) -> bool {
|
|||
|
||||
/// Return the [`Expr`] as a string literal, if it's a string or a list of strings.
|
||||
fn try_string_literal(expr: &Expr) -> Option<&str> {
|
||||
match &expr.node {
|
||||
ExprKind::List(ast::ExprList { elts, .. }) => {
|
||||
match expr {
|
||||
Expr::List(ast::ExprList { elts, .. }) => {
|
||||
if elts.is_empty() {
|
||||
None
|
||||
} else {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use num_traits::{One, Zero};
|
||||
use rustpython_parser::ast::{self, Constant, Expr, ExprKind, Keyword};
|
||||
use rustpython_parser::ast::{self, Constant, Expr, Keyword, Ranged};
|
||||
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
|
@ -33,10 +33,10 @@ pub(crate) fn snmp_insecure_version(
|
|||
{
|
||||
let call_args = SimpleCallArgs::new(args, keywords);
|
||||
if let Some(mp_model_arg) = call_args.keyword_argument("mpModel") {
|
||||
if let ExprKind::Constant(ast::ExprConstant {
|
||||
if let Expr::Constant(ast::ExprConstant {
|
||||
value: Constant::Int(value),
|
||||
..
|
||||
}) = &mp_model_arg.node
|
||||
}) = &mp_model_arg
|
||||
{
|
||||
if value.is_zero() || value.is_one() {
|
||||
checker
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use rustpython_parser::ast::{Expr, Keyword};
|
||||
use rustpython_parser::ast::{Expr, Keyword, Ranged};
|
||||
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
//! Check for calls to suspicious functions, or calls into suspicious modules.
|
||||
//!
|
||||
//! See: <https://bandit.readthedocs.io/en/latest/blacklists/blacklist_calls.html>
|
||||
use rustpython_parser::ast::{self, Expr, ExprKind};
|
||||
use rustpython_parser::ast::{self, Expr, Ranged};
|
||||
|
||||
use ruff_diagnostics::{Diagnostic, DiagnosticKind, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
|
@ -466,7 +466,7 @@ const SUSPICIOUS_MODULES: &[SuspiciousModule] = &[
|
|||
|
||||
/// S001
|
||||
pub(crate) fn suspicious_function_call(checker: &mut Checker, expr: &Expr) {
|
||||
let ExprKind::Call(ast::ExprCall { func, .. }) = &expr.node else {
|
||||
let Expr::Call(ast::ExprCall { func, .. }) = expr else {
|
||||
return;
|
||||
};
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use rustpython_parser::ast::{Excepthandler, Expr, Stmt, StmtKind};
|
||||
use rustpython_parser::ast::{Excepthandler, Expr, Ranged, Stmt};
|
||||
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
|
@ -26,7 +26,7 @@ pub(crate) fn try_except_continue(
|
|||
check_typed_exception: bool,
|
||||
) {
|
||||
if body.len() == 1
|
||||
&& body[0].node == StmtKind::Continue
|
||||
&& body[0].is_continue_stmt()
|
||||
&& (check_typed_exception || is_untyped_exception(type_, checker))
|
||||
{
|
||||
checker
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use rustpython_parser::ast::{Excepthandler, Expr, Stmt, StmtKind};
|
||||
use rustpython_parser::ast::{Excepthandler, Expr, Ranged, Stmt};
|
||||
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
|
@ -26,7 +26,7 @@ pub(crate) fn try_except_pass(
|
|||
check_typed_exception: bool,
|
||||
) {
|
||||
if body.len() == 1
|
||||
&& body[0].node == StmtKind::Pass
|
||||
&& body[0].is_pass_stmt()
|
||||
&& (check_typed_exception || is_untyped_exception(type_, checker))
|
||||
{
|
||||
checker
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use rustpython_parser::ast::{self, Expr, ExprKind, Keyword};
|
||||
use rustpython_parser::ast::{self, Expr, Keyword, Ranged};
|
||||
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
|
@ -52,9 +52,9 @@ pub(crate) fn unsafe_yaml_load(
|
|||
|| call_path.as_slice() == ["yaml", "CSafeLoader"]
|
||||
})
|
||||
{
|
||||
let loader = match &loader_arg.node {
|
||||
ExprKind::Attribute(ast::ExprAttribute { attr, .. }) => Some(attr.to_string()),
|
||||
ExprKind::Name(ast::ExprName { id, .. }) => Some(id.to_string()),
|
||||
let loader = match loader_arg {
|
||||
Expr::Attribute(ast::ExprAttribute { attr, .. }) => Some(attr.to_string()),
|
||||
Expr::Name(ast::ExprName { id, .. }) => Some(id.to_string()),
|
||||
_ => None,
|
||||
};
|
||||
checker.diagnostics.push(Diagnostic::new(
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use rustpython_parser::ast::{self, Expr, ExprKind, Stmt, StmtKind};
|
||||
use rustpython_parser::ast::{self, Expr, Ranged, Stmt};
|
||||
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
|
@ -30,16 +30,16 @@ pub(crate) fn blind_except(
|
|||
let Some(type_) = type_ else {
|
||||
return;
|
||||
};
|
||||
let ExprKind::Name(ast::ExprName { id, .. }) = &type_.node else {
|
||||
let Expr::Name(ast::ExprName { id, .. }) = &type_ else {
|
||||
return;
|
||||
};
|
||||
for exception in ["BaseException", "Exception"] {
|
||||
if id == exception && checker.ctx.is_builtin(exception) {
|
||||
// If the exception is re-raised, don't flag an error.
|
||||
if body.iter().any(|stmt| {
|
||||
if let StmtKind::Raise(ast::StmtRaise { exc, .. }) = &stmt.node {
|
||||
if let Stmt::Raise(ast::StmtRaise { exc, .. }) = stmt {
|
||||
if let Some(exc) = exc {
|
||||
if let ExprKind::Name(ast::ExprName { id, .. }) = &exc.node {
|
||||
if let Expr::Name(ast::ExprName { id, .. }) = exc.as_ref() {
|
||||
name.map_or(false, |name| id == name)
|
||||
} else {
|
||||
false
|
||||
|
@ -56,17 +56,17 @@ pub(crate) fn blind_except(
|
|||
|
||||
// If the exception is logged, don't flag an error.
|
||||
if body.iter().any(|stmt| {
|
||||
if let StmtKind::Expr(ast::StmtExpr { value }) = &stmt.node {
|
||||
if let ExprKind::Call(ast::ExprCall { func, keywords, .. }) = &value.node {
|
||||
if let Stmt::Expr(ast::StmtExpr { value, range: _ }) = stmt {
|
||||
if let Expr::Call(ast::ExprCall { func, keywords, .. }) = value.as_ref() {
|
||||
if logging::is_logger_candidate(&checker.ctx, func) {
|
||||
if let Some(attribute) = func.node.as_attribute_expr() {
|
||||
if let Some(attribute) = func.as_attribute_expr() {
|
||||
let attr = attribute.attr.as_str();
|
||||
if attr == "exception" {
|
||||
return true;
|
||||
}
|
||||
if attr == "error" {
|
||||
if let Some(keyword) = find_keyword(keywords, "exc_info") {
|
||||
if is_const_true(&keyword.node.value) {
|
||||
if is_const_true(&keyword.value) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use rustpython_parser::ast::{self, Arguments, Constant, Expr, ExprKind};
|
||||
use rustpython_parser::ast::{self, Arguments, Constant, Expr, Ranged};
|
||||
|
||||
use ruff_diagnostics::Violation;
|
||||
use ruff_diagnostics::{Diagnostic, DiagnosticKind};
|
||||
|
@ -71,11 +71,11 @@ const FUNC_DEF_NAME_ALLOWLIST: &[&str] = &["__setitem__"];
|
|||
/// `true`, the function name must be explicitly allowed, and the argument must
|
||||
/// be either the first or second argument in the call.
|
||||
fn allow_boolean_trap(func: &Expr) -> bool {
|
||||
if let ExprKind::Attribute(ast::ExprAttribute { attr, .. }) = &func.node {
|
||||
if let Expr::Attribute(ast::ExprAttribute { attr, .. }) = func {
|
||||
return FUNC_CALL_NAME_ALLOWLIST.contains(&attr.as_ref());
|
||||
}
|
||||
|
||||
if let ExprKind::Name(ast::ExprName { id, .. }) = &func.node {
|
||||
if let Expr::Name(ast::ExprName { id, .. }) = func {
|
||||
return FUNC_CALL_NAME_ALLOWLIST.contains(&id.as_ref());
|
||||
}
|
||||
|
||||
|
@ -84,8 +84,8 @@ fn allow_boolean_trap(func: &Expr) -> bool {
|
|||
|
||||
const fn is_boolean_arg(arg: &Expr) -> bool {
|
||||
matches!(
|
||||
&arg.node,
|
||||
ExprKind::Constant(ast::ExprConstant {
|
||||
&arg,
|
||||
Expr::Constant(ast::ExprConstant {
|
||||
value: Constant::Bool(_),
|
||||
..
|
||||
})
|
||||
|
@ -115,17 +115,17 @@ pub(crate) fn check_positional_boolean_in_def(
|
|||
}
|
||||
|
||||
for arg in arguments.posonlyargs.iter().chain(arguments.args.iter()) {
|
||||
if arg.node.annotation.is_none() {
|
||||
if arg.annotation.is_none() {
|
||||
continue;
|
||||
}
|
||||
let Some(expr) = &arg.node.annotation else {
|
||||
let Some(expr) = &arg.annotation else {
|
||||
continue;
|
||||
};
|
||||
|
||||
// check for both bool (python class) and 'bool' (string annotation)
|
||||
let hint = match &expr.node {
|
||||
ExprKind::Name(name) => &name.id == "bool",
|
||||
ExprKind::Constant(ast::ExprConstant {
|
||||
let hint = match expr.as_ref() {
|
||||
Expr::Name(name) => &name.id == "bool",
|
||||
Expr::Constant(ast::ExprConstant {
|
||||
value: Constant::Str(value),
|
||||
..
|
||||
}) => value == "bool",
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use rustpython_parser::ast::{self, Constant, Expr, ExprKind, Keyword, Stmt, StmtKind};
|
||||
use rustpython_parser::ast::{self, Constant, Expr, Keyword, Ranged, Stmt};
|
||||
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
|
@ -37,13 +37,9 @@ impl Violation for EmptyMethodWithoutAbstractDecorator {
|
|||
|
||||
fn is_abc_class(context: &Context, bases: &[Expr], keywords: &[Keyword]) -> bool {
|
||||
keywords.iter().any(|keyword| {
|
||||
keyword
|
||||
.node
|
||||
.arg
|
||||
.as_ref()
|
||||
.map_or(false, |arg| arg == "metaclass")
|
||||
keyword.arg.as_ref().map_or(false, |arg| arg == "metaclass")
|
||||
&& context
|
||||
.resolve_call_path(&keyword.node.value)
|
||||
.resolve_call_path(&keyword.value)
|
||||
.map_or(false, |call_path| {
|
||||
call_path.as_slice() == ["abc", "ABCMeta"]
|
||||
})
|
||||
|
@ -55,10 +51,13 @@ fn is_abc_class(context: &Context, bases: &[Expr], keywords: &[Keyword]) -> bool
|
|||
}
|
||||
|
||||
fn is_empty_body(body: &[Stmt]) -> bool {
|
||||
body.iter().all(|stmt| match &stmt.node {
|
||||
StmtKind::Pass => true,
|
||||
StmtKind::Expr(ast::StmtExpr { value }) => match &value.node {
|
||||
ExprKind::Constant(ast::ExprConstant { value, .. }) => {
|
||||
body.iter().all(|stmt| match stmt {
|
||||
Stmt::Pass(_) => true,
|
||||
Stmt::Expr(ast::StmtExpr {
|
||||
value,
|
||||
range: _range,
|
||||
}) => match value.as_ref() {
|
||||
Expr::Constant(ast::ExprConstant { value, .. }) => {
|
||||
matches!(value, Constant::Str(..) | Constant::Ellipsis)
|
||||
}
|
||||
_ => false,
|
||||
|
@ -88,24 +87,24 @@ pub(crate) fn abstract_base_class(
|
|||
for stmt in body {
|
||||
// https://github.com/PyCQA/flake8-bugbear/issues/293
|
||||
// Ignore abc's that declares a class attribute that must be set
|
||||
if let StmtKind::AnnAssign(_) | StmtKind::Assign(_) = &stmt.node {
|
||||
if let Stmt::AnnAssign(_) | Stmt::Assign(_) = stmt {
|
||||
has_abstract_method = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
let (
|
||||
StmtKind::FunctionDef(ast::StmtFunctionDef {
|
||||
Stmt::FunctionDef(ast::StmtFunctionDef {
|
||||
decorator_list,
|
||||
body,
|
||||
name: method_name,
|
||||
..
|
||||
}) | StmtKind::AsyncFunctionDef(ast::StmtAsyncFunctionDef {
|
||||
}) | Stmt::AsyncFunctionDef(ast::StmtAsyncFunctionDef {
|
||||
decorator_list,
|
||||
body,
|
||||
name: method_name,
|
||||
..
|
||||
})
|
||||
) = &stmt.node else {
|
||||
) = stmt else {
|
||||
continue;
|
||||
};
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use ruff_text_size::TextRange;
|
||||
use rustpython_parser::ast::{self, Constant, Expr, ExprContext, ExprKind, Stmt, StmtKind};
|
||||
use rustpython_parser::ast::{self, Constant, Expr, ExprContext, Ranged, Stmt};
|
||||
|
||||
use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic, Edit, Fix};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
|
@ -23,38 +23,32 @@ impl AlwaysAutofixableViolation for AssertFalse {
|
|||
}
|
||||
|
||||
fn assertion_error(msg: Option<&Expr>) -> Stmt {
|
||||
Stmt::new(
|
||||
TextRange::default(),
|
||||
StmtKind::Raise(ast::StmtRaise {
|
||||
exc: Some(Box::new(Expr::new(
|
||||
TextRange::default(),
|
||||
ExprKind::Call(ast::ExprCall {
|
||||
func: Box::new(Expr::new(
|
||||
TextRange::default(),
|
||||
ExprKind::Name(ast::ExprName {
|
||||
Stmt::Raise(ast::StmtRaise {
|
||||
range: TextRange::default(),
|
||||
exc: Some(Box::new(Expr::Call(ast::ExprCall {
|
||||
func: Box::new(Expr::Name(ast::ExprName {
|
||||
id: "AssertionError".into(),
|
||||
ctx: ExprContext::Load,
|
||||
}),
|
||||
)),
|
||||
range: TextRange::default(),
|
||||
})),
|
||||
args: if let Some(msg) = msg {
|
||||
vec![msg.clone()]
|
||||
} else {
|
||||
vec![]
|
||||
},
|
||||
keywords: vec![],
|
||||
}),
|
||||
))),
|
||||
range: TextRange::default(),
|
||||
}))),
|
||||
cause: None,
|
||||
}),
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
/// B011
|
||||
pub(crate) fn assert_false(checker: &mut Checker, stmt: &Stmt, test: &Expr, msg: Option<&Expr>) {
|
||||
let ExprKind::Constant(ast::ExprConstant {
|
||||
let Expr::Constant(ast::ExprConstant {
|
||||
value: Constant::Bool(false),
|
||||
..
|
||||
} )= &test.node else {
|
||||
} )= &test else {
|
||||
return;
|
||||
};
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use rustpython_parser::ast::{self, ExprKind, Stmt, Withitem};
|
||||
use rustpython_parser::ast::{self, Expr, Ranged, Stmt, Withitem};
|
||||
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
|
@ -55,7 +55,7 @@ pub(crate) fn assert_raises_exception(checker: &mut Checker, stmt: &Stmt, items:
|
|||
return;
|
||||
};
|
||||
let item_context = &item.context_expr;
|
||||
let ExprKind::Call(ast::ExprCall { func, args, keywords }) = &item_context.node else {
|
||||
let Expr::Call(ast::ExprCall { func, args, keywords, range: _ }) = &item_context else {
|
||||
return;
|
||||
};
|
||||
if args.len() != 1 {
|
||||
|
@ -74,7 +74,7 @@ pub(crate) fn assert_raises_exception(checker: &mut Checker, stmt: &Stmt, items:
|
|||
}
|
||||
|
||||
let kind = {
|
||||
if matches!(&func.node, ExprKind::Attribute(ast::ExprAttribute { attr, .. }) if attr == "assertRaises")
|
||||
if matches!(func.as_ref(), Expr::Attribute(ast::ExprAttribute { attr, .. }) if attr == "assertRaises")
|
||||
{
|
||||
AssertionKind::AssertRaises
|
||||
} else if checker
|
||||
|
@ -83,13 +83,9 @@ pub(crate) fn assert_raises_exception(checker: &mut Checker, stmt: &Stmt, items:
|
|||
.map_or(false, |call_path| {
|
||||
call_path.as_slice() == ["pytest", "raises"]
|
||||
})
|
||||
&& !keywords.iter().any(|keyword| {
|
||||
keyword
|
||||
.node
|
||||
.arg
|
||||
.as_ref()
|
||||
.map_or(false, |arg| arg == "match")
|
||||
})
|
||||
&& !keywords
|
||||
.iter()
|
||||
.any(|keyword| keyword.arg.as_ref().map_or(false, |arg| arg == "match"))
|
||||
{
|
||||
AssertionKind::PytestRaises
|
||||
} else {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use rustpython_parser::ast::{self, Expr, ExprKind};
|
||||
use rustpython_parser::ast::{self, Expr, Ranged};
|
||||
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
|
@ -20,13 +20,13 @@ pub(crate) fn assignment_to_os_environ(checker: &mut Checker, targets: &[Expr])
|
|||
return;
|
||||
}
|
||||
let target = &targets[0];
|
||||
let ExprKind::Attribute(ast::ExprAttribute { value, attr, .. }) = &target.node else {
|
||||
let Expr::Attribute(ast::ExprAttribute { value, attr, .. }) = target else {
|
||||
return;
|
||||
};
|
||||
if attr != "environ" {
|
||||
return;
|
||||
}
|
||||
let ExprKind::Name(ast::ExprName { id, .. } )= &value.node else {
|
||||
let Expr::Name(ast::ExprName { id, .. } )= value.as_ref() else {
|
||||
return;
|
||||
};
|
||||
if id != "os" {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use rustpython_parser::ast::{self, Expr, ExprKind};
|
||||
use rustpython_parser::ast::{self, Expr, Ranged};
|
||||
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
|
@ -36,7 +36,7 @@ pub(crate) fn cached_instance_method(checker: &mut Checker, decorator_list: &[Ex
|
|||
for decorator in decorator_list {
|
||||
// TODO(charlie): This should take into account `classmethod-decorators` and
|
||||
// `staticmethod-decorators`.
|
||||
if let ExprKind::Name(ast::ExprName { id, .. }) = &decorator.node {
|
||||
if let Expr::Name(ast::ExprName { id, .. }) = decorator {
|
||||
if id == "classmethod" || id == "staticmethod" {
|
||||
return;
|
||||
}
|
||||
|
@ -45,8 +45,8 @@ pub(crate) fn cached_instance_method(checker: &mut Checker, decorator_list: &[Ex
|
|||
for decorator in decorator_list {
|
||||
if is_cache_func(
|
||||
checker,
|
||||
match &decorator.node {
|
||||
ExprKind::Call(ast::ExprCall { func, .. }) => func,
|
||||
match decorator {
|
||||
Expr::Call(ast::ExprCall { func, .. }) => func,
|
||||
_ => decorator,
|
||||
},
|
||||
) {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use rustpython_parser::ast::{Expr, ExprKind};
|
||||
use rustpython_parser::ast::{Expr, Ranged};
|
||||
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
|
@ -17,7 +17,7 @@ impl Violation for CannotRaiseLiteral {
|
|||
|
||||
/// B016
|
||||
pub(crate) fn cannot_raise_literal(checker: &mut Checker, expr: &Expr) {
|
||||
let ExprKind::Constant ( _) = &expr.node else {
|
||||
let Expr::Constant ( _) = expr else {
|
||||
return;
|
||||
};
|
||||
checker
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use itertools::Itertools;
|
||||
use ruff_text_size::TextRange;
|
||||
use rustc_hash::{FxHashMap, FxHashSet};
|
||||
use rustpython_parser::ast::{self, Excepthandler, ExcepthandlerKind, Expr, ExprContext, ExprKind};
|
||||
use rustpython_parser::ast::{self, Excepthandler, Expr, ExprContext, Ranged};
|
||||
|
||||
use ruff_diagnostics::{AlwaysAutofixableViolation, Violation};
|
||||
use ruff_diagnostics::{Diagnostic, Edit, Fix};
|
||||
|
@ -49,13 +49,12 @@ impl AlwaysAutofixableViolation for DuplicateHandlerException {
|
|||
}
|
||||
|
||||
fn type_pattern(elts: Vec<&Expr>) -> Expr {
|
||||
Expr::new(
|
||||
TextRange::default(),
|
||||
ast::ExprTuple {
|
||||
elts: elts.into_iter().cloned().collect(),
|
||||
ctx: ExprContext::Load,
|
||||
},
|
||||
)
|
||||
range: TextRange::default(),
|
||||
}
|
||||
.into()
|
||||
}
|
||||
|
||||
fn duplicate_handler_exceptions<'a>(
|
||||
|
@ -116,11 +115,11 @@ pub(crate) fn duplicate_exceptions(checker: &mut Checker, handlers: &[Excepthand
|
|||
let mut seen: FxHashSet<CallPath> = FxHashSet::default();
|
||||
let mut duplicates: FxHashMap<CallPath, Vec<&Expr>> = FxHashMap::default();
|
||||
for handler in handlers {
|
||||
let ExcepthandlerKind::ExceptHandler(ast::ExcepthandlerExceptHandler { type_: Some(type_), .. }) = &handler.node else {
|
||||
let Excepthandler::ExceptHandler(ast::ExcepthandlerExceptHandler { type_: Some(type_), .. }) = handler else {
|
||||
continue;
|
||||
};
|
||||
match &type_.node {
|
||||
ExprKind::Attribute(_) | ExprKind::Name(_) => {
|
||||
match type_.as_ref() {
|
||||
Expr::Attribute(_) | Expr::Name(_) => {
|
||||
if let Some(call_path) = call_path::collect_call_path(type_) {
|
||||
if seen.contains(&call_path) {
|
||||
duplicates.entry(call_path).or_default().push(type_);
|
||||
|
@ -129,7 +128,7 @@ pub(crate) fn duplicate_exceptions(checker: &mut Checker, handlers: &[Excepthand
|
|||
}
|
||||
}
|
||||
}
|
||||
ExprKind::Tuple(ast::ExprTuple { elts, .. }) => {
|
||||
Expr::Tuple(ast::ExprTuple { elts, .. }) => {
|
||||
for (name, expr) in duplicate_handler_exceptions(checker, type_, elts) {
|
||||
if seen.contains(&name) {
|
||||
duplicates.entry(name).or_default().push(expr);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use rustpython_parser::ast::Excepthandler;
|
||||
use rustpython_parser::ast::{self, ExcepthandlerKind, ExprKind};
|
||||
use rustpython_parser::ast::{self, Ranged};
|
||||
use rustpython_parser::ast::{Excepthandler, Expr};
|
||||
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
|
@ -18,12 +18,11 @@ impl Violation for ExceptWithEmptyTuple {
|
|||
|
||||
/// B029
|
||||
pub(crate) fn except_with_empty_tuple(checker: &mut Checker, excepthandler: &Excepthandler) {
|
||||
let ExcepthandlerKind::ExceptHandler(ast::ExcepthandlerExceptHandler { type_, .. }) =
|
||||
&excepthandler.node;
|
||||
let Excepthandler::ExceptHandler(ast::ExcepthandlerExceptHandler { type_, .. }) = excepthandler;
|
||||
let Some(type_) = type_ else {
|
||||
return;
|
||||
};
|
||||
let ExprKind::Tuple(ast::ExprTuple { elts, .. }) = &type_.node else {
|
||||
let Expr::Tuple(ast::ExprTuple { elts, .. }) = type_.as_ref() else {
|
||||
return;
|
||||
};
|
||||
if elts.is_empty() {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use std::collections::VecDeque;
|
||||
|
||||
use rustpython_parser::ast::{self, Excepthandler, ExcepthandlerKind, Expr, ExprKind};
|
||||
use rustpython_parser::ast::{self, Excepthandler, Expr, Ranged};
|
||||
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
|
@ -17,20 +17,20 @@ impl Violation for ExceptWithNonExceptionClasses {
|
|||
}
|
||||
}
|
||||
|
||||
/// Given an [`Expr`], flatten any [`ExprKind::Starred`] expressions.
|
||||
/// Given an [`Expr`], flatten any [`Expr::Starred`] expressions.
|
||||
/// This should leave any unstarred iterables alone (subsequently raising a
|
||||
/// warning for B029).
|
||||
fn flatten_starred_iterables(expr: &Expr) -> Vec<&Expr> {
|
||||
let ExprKind::Tuple(ast::ExprTuple { elts, .. } )= &expr.node else {
|
||||
let Expr::Tuple(ast::ExprTuple { elts, .. } )= expr else {
|
||||
return vec![expr];
|
||||
};
|
||||
let mut flattened_exprs: Vec<&Expr> = Vec::with_capacity(elts.len());
|
||||
let mut exprs_to_process: VecDeque<&Expr> = elts.iter().collect();
|
||||
while let Some(expr) = exprs_to_process.pop_front() {
|
||||
match &expr.node {
|
||||
ExprKind::Starred(ast::ExprStarred { value, .. }) => match &value.node {
|
||||
ExprKind::Tuple(ast::ExprTuple { elts, .. })
|
||||
| ExprKind::List(ast::ExprList { elts, .. }) => {
|
||||
match expr {
|
||||
Expr::Starred(ast::ExprStarred { value, .. }) => match value.as_ref() {
|
||||
Expr::Tuple(ast::ExprTuple { elts, .. })
|
||||
| Expr::List(ast::ExprList { elts, .. }) => {
|
||||
exprs_to_process.append(&mut elts.iter().collect());
|
||||
}
|
||||
_ => flattened_exprs.push(value),
|
||||
|
@ -46,15 +46,14 @@ pub(crate) fn except_with_non_exception_classes(
|
|||
checker: &mut Checker,
|
||||
excepthandler: &Excepthandler,
|
||||
) {
|
||||
let ExcepthandlerKind::ExceptHandler(ast::ExcepthandlerExceptHandler { type_, .. }) =
|
||||
&excepthandler.node;
|
||||
let Excepthandler::ExceptHandler(ast::ExcepthandlerExceptHandler { type_, .. }) = excepthandler;
|
||||
let Some(type_) = type_ else {
|
||||
return;
|
||||
};
|
||||
for expr in flatten_starred_iterables(type_) {
|
||||
if !matches!(
|
||||
&expr.node,
|
||||
ExprKind::Subscript(_) | ExprKind::Attribute(_) | ExprKind::Name(_) | ExprKind::Call(_),
|
||||
expr,
|
||||
Expr::Subscript(_) | Expr::Attribute(_) | Expr::Name(_) | Expr::Call(_),
|
||||
) {
|
||||
checker
|
||||
.diagnostics
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use rustpython_parser::ast::{self, ExprKind, Stmt, StmtKind};
|
||||
use rustpython_parser::ast::{self, Expr, Stmt};
|
||||
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
|
@ -23,10 +23,10 @@ pub(crate) fn f_string_docstring(checker: &mut Checker, body: &[Stmt]) {
|
|||
let Some(stmt) = body.first() else {
|
||||
return;
|
||||
};
|
||||
let StmtKind::Expr(ast::StmtExpr { value }) = &stmt.node else {
|
||||
let Stmt::Expr(ast::StmtExpr { value, range: _ }) = stmt else {
|
||||
return;
|
||||
};
|
||||
let ExprKind::JoinedStr ( _) = value.node else {
|
||||
let Expr::JoinedStr ( _) = value.as_ref() else {
|
||||
return;
|
||||
};
|
||||
checker.diagnostics.push(Diagnostic::new(
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use ruff_text_size::TextRange;
|
||||
use rustpython_parser::ast::{self, Arguments, Constant, Expr, ExprKind};
|
||||
use rustpython_parser::ast::{self, Arguments, Constant, Expr, Ranged};
|
||||
|
||||
use ruff_diagnostics::Violation;
|
||||
use ruff_diagnostics::{Diagnostic, DiagnosticKind};
|
||||
|
@ -83,8 +83,8 @@ where
|
|||
'b: 'a,
|
||||
{
|
||||
fn visit_expr(&mut self, expr: &'b Expr) {
|
||||
match &expr.node {
|
||||
ExprKind::Call(ast::ExprCall { func, args, .. }) => {
|
||||
match expr {
|
||||
Expr::Call(ast::ExprCall { func, args, .. }) => {
|
||||
if !is_mutable_func(self.checker, func)
|
||||
&& !is_immutable_func(&self.checker.ctx, func, &self.extend_immutable_calls)
|
||||
&& !is_nan_or_infinity(func, args)
|
||||
|
@ -99,14 +99,14 @@ where
|
|||
}
|
||||
visitor::walk_expr(self, expr);
|
||||
}
|
||||
ExprKind::Lambda(_) => {}
|
||||
Expr::Lambda(_) => {}
|
||||
_ => visitor::walk_expr(self, expr),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn is_nan_or_infinity(expr: &Expr, args: &[Expr]) -> bool {
|
||||
let ExprKind::Name(ast::ExprName { id, .. }) = &expr.node else {
|
||||
let Expr::Name(ast::ExprName { id, .. }) = expr else {
|
||||
return false;
|
||||
};
|
||||
if id != "float" {
|
||||
|
@ -115,10 +115,10 @@ fn is_nan_or_infinity(expr: &Expr, args: &[Expr]) -> bool {
|
|||
let Some(arg) = args.first() else {
|
||||
return false;
|
||||
};
|
||||
let ExprKind::Constant(ast::ExprConstant {
|
||||
let Expr::Constant(ast::ExprConstant {
|
||||
value: Constant::Str(value),
|
||||
..
|
||||
} )= &arg.node else {
|
||||
} )= arg else {
|
||||
return false;
|
||||
};
|
||||
let lowercased = value.to_lowercase();
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
use ruff_text_size::TextRange;
|
||||
use rustc_hash::FxHashSet;
|
||||
use rustpython_parser::ast::{self, Comprehension, Expr, ExprContext, ExprKind, Stmt, StmtKind};
|
||||
use rustpython_parser::ast::{self, Comprehension, Expr, ExprContext, Ranged, Stmt};
|
||||
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
|
@ -27,18 +26,18 @@ impl Violation for FunctionUsesLoopVariable {
|
|||
#[derive(Default)]
|
||||
struct LoadedNamesVisitor<'a> {
|
||||
// Tuple of: name, defining expression, and defining range.
|
||||
loaded: Vec<(&'a str, &'a Expr, TextRange)>,
|
||||
loaded: Vec<(&'a str, &'a Expr)>,
|
||||
// Tuple of: name, defining expression, and defining range.
|
||||
stored: Vec<(&'a str, &'a Expr, TextRange)>,
|
||||
stored: Vec<(&'a str, &'a Expr)>,
|
||||
}
|
||||
|
||||
/// `Visitor` to collect all used identifiers in a statement.
|
||||
impl<'a> Visitor<'a> for LoadedNamesVisitor<'a> {
|
||||
fn visit_expr(&mut self, expr: &'a Expr) {
|
||||
match &expr.node {
|
||||
ExprKind::Name(ast::ExprName { id, ctx }) => match ctx {
|
||||
ExprContext::Load => self.loaded.push((id, expr, expr.range())),
|
||||
ExprContext::Store => self.stored.push((id, expr, expr.range())),
|
||||
match expr {
|
||||
Expr::Name(ast::ExprName { id, ctx, range: _ }) => match ctx {
|
||||
ExprContext::Load => self.loaded.push((id, expr)),
|
||||
ExprContext::Store => self.stored.push((id, expr)),
|
||||
ExprContext::Del => {}
|
||||
},
|
||||
_ => visitor::walk_expr(self, expr),
|
||||
|
@ -48,7 +47,7 @@ impl<'a> Visitor<'a> for LoadedNamesVisitor<'a> {
|
|||
|
||||
#[derive(Default)]
|
||||
struct SuspiciousVariablesVisitor<'a> {
|
||||
names: Vec<(&'a str, &'a Expr, TextRange)>,
|
||||
names: Vec<(&'a str, &'a Expr)>,
|
||||
safe_functions: Vec<&'a Expr>,
|
||||
}
|
||||
|
||||
|
@ -56,9 +55,9 @@ struct SuspiciousVariablesVisitor<'a> {
|
|||
/// functions, but not bound as arguments).
|
||||
impl<'a> Visitor<'a> for SuspiciousVariablesVisitor<'a> {
|
||||
fn visit_stmt(&mut self, stmt: &'a Stmt) {
|
||||
match &stmt.node {
|
||||
StmtKind::FunctionDef(ast::StmtFunctionDef { args, body, .. })
|
||||
| StmtKind::AsyncFunctionDef(ast::StmtAsyncFunctionDef { args, body, .. }) => {
|
||||
match stmt {
|
||||
Stmt::FunctionDef(ast::StmtFunctionDef { args, body, .. })
|
||||
| Stmt::AsyncFunctionDef(ast::StmtAsyncFunctionDef { args, body, .. }) => {
|
||||
// Collect all loaded variable names.
|
||||
let mut visitor = LoadedNamesVisitor::default();
|
||||
visitor.visit_body(body);
|
||||
|
@ -76,9 +75,12 @@ impl<'a> Visitor<'a> for SuspiciousVariablesVisitor<'a> {
|
|||
);
|
||||
return;
|
||||
}
|
||||
StmtKind::Return(ast::StmtReturn { value: Some(value) }) => {
|
||||
Stmt::Return(ast::StmtReturn {
|
||||
value: Some(value),
|
||||
range: _,
|
||||
}) => {
|
||||
// Mark `return lambda: x` as safe.
|
||||
if matches!(value.node, ExprKind::Lambda(_)) {
|
||||
if value.is_lambda_expr() {
|
||||
self.safe_functions.push(value);
|
||||
}
|
||||
}
|
||||
|
@ -88,28 +90,30 @@ impl<'a> Visitor<'a> for SuspiciousVariablesVisitor<'a> {
|
|||
}
|
||||
|
||||
fn visit_expr(&mut self, expr: &'a Expr) {
|
||||
match &expr.node {
|
||||
ExprKind::Call(ast::ExprCall {
|
||||
match expr {
|
||||
Expr::Call(ast::ExprCall {
|
||||
func,
|
||||
args,
|
||||
keywords,
|
||||
range: _,
|
||||
}) => {
|
||||
if let ExprKind::Name(ast::ExprName { id, .. }) = &func.node {
|
||||
match func.as_ref() {
|
||||
Expr::Name(ast::ExprName { id, .. }) => {
|
||||
let id = id.as_str();
|
||||
if id == "filter" || id == "reduce" || id == "map" {
|
||||
for arg in args {
|
||||
if matches!(arg.node, ExprKind::Lambda(_)) {
|
||||
if matches!(arg, Expr::Lambda(_)) {
|
||||
self.safe_functions.push(arg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if let ExprKind::Attribute(ast::ExprAttribute { value, attr, .. }) = &func.node {
|
||||
Expr::Attribute(ast::ExprAttribute { value, attr, .. }) => {
|
||||
if attr == "reduce" {
|
||||
if let ExprKind::Name(ast::ExprName { id, .. }) = &value.node {
|
||||
if let Expr::Name(ast::ExprName { id, .. }) = value.as_ref() {
|
||||
if id == "functools" {
|
||||
for arg in args {
|
||||
if matches!(arg.node, ExprKind::Lambda(_)) {
|
||||
if arg.is_lambda_expr() {
|
||||
self.safe_functions.push(arg);
|
||||
}
|
||||
}
|
||||
|
@ -117,15 +121,22 @@ impl<'a> Visitor<'a> for SuspiciousVariablesVisitor<'a> {
|
|||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
for keyword in keywords {
|
||||
if keyword.node.arg.as_ref().map_or(false, |arg| arg == "key")
|
||||
&& matches!(keyword.node.value.node, ExprKind::Lambda(_))
|
||||
if keyword.arg.as_ref().map_or(false, |arg| arg == "key")
|
||||
&& matches!(keyword.value, Expr::Lambda(_))
|
||||
{
|
||||
self.safe_functions.push(&keyword.node.value);
|
||||
self.safe_functions.push(&keyword.value);
|
||||
}
|
||||
}
|
||||
}
|
||||
ExprKind::Lambda(ast::ExprLambda { args, body }) => {
|
||||
Expr::Lambda(ast::ExprLambda {
|
||||
args,
|
||||
body,
|
||||
range: _,
|
||||
}) => {
|
||||
if !self.safe_functions.contains(&expr) {
|
||||
// Collect all loaded variable names.
|
||||
let mut visitor = LoadedNamesVisitor::default();
|
||||
|
@ -160,15 +171,14 @@ struct NamesFromAssignmentsVisitor<'a> {
|
|||
/// `Visitor` to collect all names used in an assignment expression.
|
||||
impl<'a> Visitor<'a> for NamesFromAssignmentsVisitor<'a> {
|
||||
fn visit_expr(&mut self, expr: &'a Expr) {
|
||||
match &expr.node {
|
||||
ExprKind::Name(ast::ExprName { id, .. }) => {
|
||||
match expr {
|
||||
Expr::Name(ast::ExprName { id, .. }) => {
|
||||
self.names.insert(id.as_str());
|
||||
}
|
||||
ExprKind::Starred(ast::ExprStarred { value, .. }) => {
|
||||
Expr::Starred(ast::ExprStarred { value, .. }) => {
|
||||
self.visit_expr(value);
|
||||
}
|
||||
ExprKind::List(ast::ExprList { elts, .. })
|
||||
| ExprKind::Tuple(ast::ExprTuple { elts, .. }) => {
|
||||
Expr::List(ast::ExprList { elts, .. }) | Expr::Tuple(ast::ExprTuple { elts, .. }) => {
|
||||
for expr in elts {
|
||||
self.visit_expr(expr);
|
||||
}
|
||||
|
@ -186,26 +196,23 @@ struct AssignedNamesVisitor<'a> {
|
|||
/// `Visitor` to collect all used identifiers in a statement.
|
||||
impl<'a> Visitor<'a> for AssignedNamesVisitor<'a> {
|
||||
fn visit_stmt(&mut self, stmt: &'a Stmt) {
|
||||
if matches!(
|
||||
&stmt.node,
|
||||
StmtKind::FunctionDef(_) | StmtKind::AsyncFunctionDef(_)
|
||||
) {
|
||||
if matches!(stmt, Stmt::FunctionDef(_) | Stmt::AsyncFunctionDef(_)) {
|
||||
// Don't recurse.
|
||||
return;
|
||||
}
|
||||
|
||||
match &stmt.node {
|
||||
StmtKind::Assign(ast::StmtAssign { targets, .. }) => {
|
||||
match stmt {
|
||||
Stmt::Assign(ast::StmtAssign { targets, .. }) => {
|
||||
let mut visitor = NamesFromAssignmentsVisitor::default();
|
||||
for expr in targets {
|
||||
visitor.visit_expr(expr);
|
||||
}
|
||||
self.names.extend(visitor.names);
|
||||
}
|
||||
StmtKind::AugAssign(ast::StmtAugAssign { target, .. })
|
||||
| StmtKind::AnnAssign(ast::StmtAnnAssign { target, .. })
|
||||
| StmtKind::For(ast::StmtFor { target, .. })
|
||||
| StmtKind::AsyncFor(ast::StmtAsyncFor { target, .. }) => {
|
||||
Stmt::AugAssign(ast::StmtAugAssign { target, .. })
|
||||
| Stmt::AnnAssign(ast::StmtAnnAssign { target, .. })
|
||||
| Stmt::For(ast::StmtFor { target, .. })
|
||||
| Stmt::AsyncFor(ast::StmtAsyncFor { target, .. }) => {
|
||||
let mut visitor = NamesFromAssignmentsVisitor::default();
|
||||
visitor.visit_expr(target);
|
||||
self.names.extend(visitor.names);
|
||||
|
@ -217,7 +224,7 @@ impl<'a> Visitor<'a> for AssignedNamesVisitor<'a> {
|
|||
}
|
||||
|
||||
fn visit_expr(&mut self, expr: &'a Expr) {
|
||||
if matches!(&expr.node, ExprKind::Lambda(_)) {
|
||||
if matches!(expr, Expr::Lambda(_)) {
|
||||
// Don't recurse.
|
||||
return;
|
||||
}
|
||||
|
@ -260,7 +267,7 @@ pub(crate) fn function_uses_loop_variable<'a>(checker: &mut Checker<'a>, node: &
|
|||
|
||||
// If a variable was used in a function or lambda body, and assigned in the
|
||||
// loop, flag it.
|
||||
for (name, expr, range) in suspicious_variables {
|
||||
for (name, expr) in suspicious_variables {
|
||||
if reassigned_in_loop.contains(name) {
|
||||
if !checker.flake8_bugbear_seen.contains(&expr) {
|
||||
checker.flake8_bugbear_seen.push(expr);
|
||||
|
@ -268,7 +275,7 @@ pub(crate) fn function_uses_loop_variable<'a>(checker: &mut Checker<'a>, node: &
|
|||
FunctionUsesLoopVariable {
|
||||
name: name.to_string(),
|
||||
},
|
||||
range,
|
||||
expr.range(),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use ruff_text_size::TextRange;
|
||||
use rustpython_parser::ast::{self, Constant, Expr, ExprContext, ExprKind};
|
||||
use rustpython_parser::ast::{self, Constant, Expr, ExprContext, Ranged};
|
||||
|
||||
use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic, Edit, Fix};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
|
@ -26,14 +26,13 @@ impl AlwaysAutofixableViolation for GetAttrWithConstant {
|
|||
}
|
||||
}
|
||||
fn attribute(value: &Expr, attr: &str) -> Expr {
|
||||
Expr::new(
|
||||
TextRange::default(),
|
||||
ast::ExprAttribute {
|
||||
value: Box::new(value.clone()),
|
||||
attr: attr.into(),
|
||||
ctx: ExprContext::Load,
|
||||
},
|
||||
)
|
||||
range: TextRange::default(),
|
||||
}
|
||||
.into()
|
||||
}
|
||||
|
||||
/// B009
|
||||
|
@ -43,7 +42,7 @@ pub(crate) fn getattr_with_constant(
|
|||
func: &Expr,
|
||||
args: &[Expr],
|
||||
) {
|
||||
let ExprKind::Name(ast::ExprName { id, .. } )= &func.node else {
|
||||
let Expr::Name(ast::ExprName { id, .. } )= func else {
|
||||
return;
|
||||
};
|
||||
if id != "getattr" {
|
||||
|
@ -52,10 +51,10 @@ pub(crate) fn getattr_with_constant(
|
|||
let [obj, arg] = args else {
|
||||
return;
|
||||
};
|
||||
let ExprKind::Constant(ast::ExprConstant {
|
||||
let Expr::Constant(ast::ExprConstant {
|
||||
value: Constant::Str(value),
|
||||
..
|
||||
} )= &arg.node else {
|
||||
} )= arg else {
|
||||
return;
|
||||
};
|
||||
if !is_identifier(value) {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use rustpython_parser::ast::{self, Stmt, StmtKind};
|
||||
use rustpython_parser::ast::{self, Ranged, Stmt};
|
||||
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
|
@ -23,35 +23,31 @@ fn walk_stmt(checker: &mut Checker, body: &[Stmt], f: fn(&Stmt) -> bool) {
|
|||
if f(stmt) {
|
||||
checker.diagnostics.push(Diagnostic::new(
|
||||
JumpStatementInFinally {
|
||||
name: match &stmt.node {
|
||||
StmtKind::Break => "break",
|
||||
StmtKind::Continue => "continue",
|
||||
StmtKind::Return(_) => "return",
|
||||
_ => unreachable!(
|
||||
"Expected StmtKind::Break | StmtKind::Continue | StmtKind::Return"
|
||||
),
|
||||
name: match stmt {
|
||||
Stmt::Break(_) => "break",
|
||||
Stmt::Continue(_) => "continue",
|
||||
Stmt::Return(_) => "return",
|
||||
_ => unreachable!("Expected Stmt::Break | Stmt::Continue | Stmt::Return"),
|
||||
}
|
||||
.to_owned(),
|
||||
},
|
||||
stmt.range(),
|
||||
));
|
||||
}
|
||||
match &stmt.node {
|
||||
StmtKind::While(ast::StmtWhile { body, .. })
|
||||
| StmtKind::For(ast::StmtFor { body, .. })
|
||||
| StmtKind::AsyncFor(ast::StmtAsyncFor { body, .. }) => {
|
||||
walk_stmt(checker, body, |stmt| {
|
||||
matches!(stmt.node, StmtKind::Return(_))
|
||||
});
|
||||
match stmt {
|
||||
Stmt::While(ast::StmtWhile { body, .. })
|
||||
| Stmt::For(ast::StmtFor { body, .. })
|
||||
| Stmt::AsyncFor(ast::StmtAsyncFor { body, .. }) => {
|
||||
walk_stmt(checker, body, |stmt| matches!(stmt, Stmt::Return(_)));
|
||||
}
|
||||
StmtKind::If(ast::StmtIf { body, .. })
|
||||
| StmtKind::Try(ast::StmtTry { body, .. })
|
||||
| StmtKind::TryStar(ast::StmtTryStar { body, .. })
|
||||
| StmtKind::With(ast::StmtWith { body, .. })
|
||||
| StmtKind::AsyncWith(ast::StmtAsyncWith { body, .. }) => {
|
||||
Stmt::If(ast::StmtIf { body, .. })
|
||||
| Stmt::Try(ast::StmtTry { body, .. })
|
||||
| Stmt::TryStar(ast::StmtTryStar { body, .. })
|
||||
| Stmt::With(ast::StmtWith { body, .. })
|
||||
| Stmt::AsyncWith(ast::StmtAsyncWith { body, .. }) => {
|
||||
walk_stmt(checker, body, f);
|
||||
}
|
||||
StmtKind::Match(ast::StmtMatch { cases, .. }) => {
|
||||
Stmt::Match(ast::StmtMatch { cases, .. }) => {
|
||||
for case in cases {
|
||||
walk_stmt(checker, &case.body, f);
|
||||
}
|
||||
|
@ -64,9 +60,6 @@ fn walk_stmt(checker: &mut Checker, body: &[Stmt], f: fn(&Stmt) -> bool) {
|
|||
/// B012
|
||||
pub(crate) fn jump_statement_in_finally(checker: &mut Checker, finalbody: &[Stmt]) {
|
||||
walk_stmt(checker, finalbody, |stmt| {
|
||||
matches!(
|
||||
stmt.node,
|
||||
StmtKind::Break | StmtKind::Continue | StmtKind::Return(_)
|
||||
)
|
||||
matches!(stmt, Stmt::Break(_) | Stmt::Continue(_) | Stmt::Return(_))
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use rustc_hash::FxHashMap;
|
||||
use rustpython_parser::ast::{self, Expr, ExprKind};
|
||||
use rustpython_parser::ast::{self, Expr, Ranged};
|
||||
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
|
@ -31,22 +31,26 @@ where
|
|||
'b: 'a,
|
||||
{
|
||||
fn visit_expr(&mut self, expr: &'b Expr) {
|
||||
match &expr.node {
|
||||
ExprKind::Name(ast::ExprName { id, .. }) => {
|
||||
match expr {
|
||||
Expr::Name(ast::ExprName { id, .. }) => {
|
||||
self.names.insert(id, expr);
|
||||
}
|
||||
ExprKind::ListComp(ast::ExprListComp { generators, .. })
|
||||
| ExprKind::DictComp(ast::ExprDictComp { generators, .. })
|
||||
| ExprKind::SetComp(ast::ExprSetComp { generators, .. })
|
||||
| ExprKind::GeneratorExp(ast::ExprGeneratorExp { generators, .. }) => {
|
||||
Expr::ListComp(ast::ExprListComp { generators, .. })
|
||||
| Expr::DictComp(ast::ExprDictComp { generators, .. })
|
||||
| Expr::SetComp(ast::ExprSetComp { generators, .. })
|
||||
| Expr::GeneratorExp(ast::ExprGeneratorExp { generators, .. }) => {
|
||||
for comp in generators {
|
||||
self.visit_expr(&comp.iter);
|
||||
}
|
||||
}
|
||||
ExprKind::Lambda(ast::ExprLambda { args, body }) => {
|
||||
Expr::Lambda(ast::ExprLambda {
|
||||
args,
|
||||
body,
|
||||
range: _,
|
||||
}) => {
|
||||
visitor::walk_expr(self, body);
|
||||
for arg in &args.args {
|
||||
self.names.remove(arg.node.arg.as_str());
|
||||
self.names.remove(arg.arg.as_str());
|
||||
}
|
||||
}
|
||||
_ => visitor::walk_expr(self, expr),
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use rustpython_parser::ast::{self, Arguments, Expr, ExprKind};
|
||||
use rustpython_parser::ast::{self, Arguments, Expr, Ranged};
|
||||
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
|
@ -37,14 +37,14 @@ pub(crate) fn is_mutable_func(checker: &Checker, func: &Expr) -> bool {
|
|||
}
|
||||
|
||||
fn is_mutable_expr(checker: &Checker, expr: &Expr) -> bool {
|
||||
match &expr.node {
|
||||
ExprKind::List(_)
|
||||
| ExprKind::Dict(_)
|
||||
| ExprKind::Set(_)
|
||||
| ExprKind::ListComp(_)
|
||||
| ExprKind::DictComp(_)
|
||||
| ExprKind::SetComp(_) => true,
|
||||
ExprKind::Call(ast::ExprCall { func, .. }) => is_mutable_func(checker, func),
|
||||
match expr {
|
||||
Expr::List(_)
|
||||
| Expr::Dict(_)
|
||||
| Expr::Set(_)
|
||||
| Expr::ListComp(_)
|
||||
| Expr::DictComp(_)
|
||||
| Expr::SetComp(_) => true,
|
||||
Expr::Call(ast::ExprCall { func, .. }) => is_mutable_func(checker, func),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
@ -68,7 +68,6 @@ pub(crate) fn mutable_argument_default(checker: &mut Checker, arguments: &Argume
|
|||
{
|
||||
if is_mutable_expr(checker, default)
|
||||
&& !arg
|
||||
.node
|
||||
.annotation
|
||||
.as_ref()
|
||||
.map_or(false, |expr| is_immutable_annotation(&checker.ctx, expr))
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use rustpython_parser::ast::{Expr, Keyword};
|
||||
use rustpython_parser::ast::{Expr, Keyword, Ranged};
|
||||
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use rustpython_parser::ast::{self, ExprKind, Stmt};
|
||||
use rustpython_parser::ast::{self, Expr, Stmt};
|
||||
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
|
@ -32,8 +32,8 @@ pub(crate) fn raise_without_from_inside_except(checker: &mut Checker, body: &[St
|
|||
for (range, exc, cause) in raises {
|
||||
if cause.is_none() {
|
||||
if let Some(exc) = exc {
|
||||
match &exc.node {
|
||||
ExprKind::Name(ast::ExprName { id, .. }) if is_lower(id) => {}
|
||||
match exc {
|
||||
Expr::Name(ast::ExprName { id, .. }) if is_lower(id) => {}
|
||||
_ => {
|
||||
checker
|
||||
.diagnostics
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use rustpython_parser::ast::{self, Excepthandler, ExcepthandlerKind, ExprKind};
|
||||
use rustpython_parser::ast::{self, Excepthandler, Expr, Ranged};
|
||||
|
||||
use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic, Edit, Fix};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
|
@ -34,10 +34,10 @@ pub(crate) fn redundant_tuple_in_exception_handler(
|
|||
handlers: &[Excepthandler],
|
||||
) {
|
||||
for handler in handlers {
|
||||
let ExcepthandlerKind::ExceptHandler(ast::ExcepthandlerExceptHandler { type_: Some(type_), .. }) = &handler.node else {
|
||||
let Excepthandler::ExceptHandler(ast::ExcepthandlerExceptHandler { type_: Some(type_), .. }) = handler else {
|
||||
continue;
|
||||
};
|
||||
let ExprKind::Tuple(ast::ExprTuple { elts, .. }) = &type_.node else {
|
||||
let Expr::Tuple(ast::ExprTuple { elts, .. }) = type_.as_ref() else {
|
||||
continue;
|
||||
};
|
||||
let [elt] = &elts[..] else {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use rustpython_parser::ast::{self, Comprehension, Expr, ExprKind, Stmt, StmtKind};
|
||||
use rustpython_parser::ast::{self, Comprehension, Expr, Ranged, Stmt};
|
||||
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
|
@ -84,7 +84,7 @@ impl<'a> GroupNameFinder<'a> {
|
|||
}
|
||||
|
||||
fn name_matches(&self, expr: &Expr) -> bool {
|
||||
if let ExprKind::Name(ast::ExprName { id, .. }) = &expr.node {
|
||||
if let Expr::Name(ast::ExprName { id, .. }) = expr {
|
||||
id == self.group_name
|
||||
} else {
|
||||
false
|
||||
|
@ -112,8 +112,8 @@ where
|
|||
if self.overridden {
|
||||
return;
|
||||
}
|
||||
match &stmt.node {
|
||||
StmtKind::For(ast::StmtFor {
|
||||
match stmt {
|
||||
Stmt::For(ast::StmtFor {
|
||||
target, iter, body, ..
|
||||
}) => {
|
||||
if self.name_matches(target) {
|
||||
|
@ -138,15 +138,20 @@ where
|
|||
self.nested = false;
|
||||
}
|
||||
}
|
||||
StmtKind::While(ast::StmtWhile { body, .. }) => {
|
||||
Stmt::While(ast::StmtWhile { body, .. }) => {
|
||||
self.nested = true;
|
||||
visitor::walk_body(self, body);
|
||||
self.nested = false;
|
||||
}
|
||||
StmtKind::If(ast::StmtIf { test, body, orelse }) => {
|
||||
Stmt::If(ast::StmtIf {
|
||||
test,
|
||||
body,
|
||||
orelse,
|
||||
range: _,
|
||||
}) => {
|
||||
// Determine whether we're on an `if` arm (as opposed to an `elif`).
|
||||
let is_if_arm = !self.parent_ifs.iter().any(|parent| {
|
||||
if let StmtKind::If(ast::StmtIf { orelse, .. }) = &parent.node {
|
||||
if let Stmt::If(ast::StmtIf { orelse, .. }) = parent {
|
||||
orelse.len() == 1 && &orelse[0] == stmt
|
||||
} else {
|
||||
false
|
||||
|
@ -166,12 +171,12 @@ where
|
|||
|
||||
let has_else = orelse
|
||||
.first()
|
||||
.map_or(false, |expr| !matches!(expr.node, StmtKind::If(_)));
|
||||
.map_or(false, |expr| !matches!(expr, Stmt::If(_)));
|
||||
|
||||
self.parent_ifs.push(stmt);
|
||||
if has_else {
|
||||
// There's no `StmtKind::Else`; instead, the `else` contents are directly on
|
||||
// the `orelse` of the `StmtKind::If` node. We want to add a new counter for
|
||||
// There's no `Stmt::Else`; instead, the `else` contents are directly on
|
||||
// the `orelse` of the `Stmt::If` node. We want to add a new counter for
|
||||
// the `orelse` branch, but first, we need to visit the `if` body manually.
|
||||
self.visit_expr(test);
|
||||
self.visit_body(body);
|
||||
|
@ -193,7 +198,11 @@ where
|
|||
}
|
||||
}
|
||||
}
|
||||
StmtKind::Match(ast::StmtMatch { subject, cases }) => {
|
||||
Stmt::Match(ast::StmtMatch {
|
||||
subject,
|
||||
cases,
|
||||
range: _,
|
||||
}) => {
|
||||
self.counter_stack.push(Vec::with_capacity(cases.len()));
|
||||
self.visit_expr(subject);
|
||||
for match_case in cases {
|
||||
|
@ -207,14 +216,14 @@ where
|
|||
self.increment_usage_count(max_count);
|
||||
}
|
||||
}
|
||||
StmtKind::Assign(ast::StmtAssign { targets, value, .. }) => {
|
||||
Stmt::Assign(ast::StmtAssign { targets, value, .. }) => {
|
||||
if targets.iter().any(|target| self.name_matches(target)) {
|
||||
self.overridden = true;
|
||||
} else {
|
||||
self.visit_expr(value);
|
||||
}
|
||||
}
|
||||
StmtKind::AnnAssign(ast::StmtAnnAssign { target, value, .. }) => {
|
||||
Stmt::AnnAssign(ast::StmtAnnAssign { target, value, .. }) => {
|
||||
if self.name_matches(target) {
|
||||
self.overridden = true;
|
||||
} else if let Some(expr) = value {
|
||||
|
@ -241,7 +250,7 @@ where
|
|||
}
|
||||
|
||||
fn visit_expr(&mut self, expr: &'a Expr) {
|
||||
if let ExprKind::NamedExpr(ast::ExprNamedExpr { target, .. }) = &expr.node {
|
||||
if let Expr::NamedExpr(ast::ExprNamedExpr { target, .. }) = expr {
|
||||
if self.name_matches(target) {
|
||||
self.overridden = true;
|
||||
}
|
||||
|
@ -250,9 +259,17 @@ where
|
|||
return;
|
||||
}
|
||||
|
||||
match &expr.node {
|
||||
ExprKind::ListComp(ast::ExprListComp { elt, generators })
|
||||
| ExprKind::SetComp(ast::ExprSetComp { elt, generators }) => {
|
||||
match expr {
|
||||
Expr::ListComp(ast::ExprListComp {
|
||||
elt,
|
||||
generators,
|
||||
range: _,
|
||||
})
|
||||
| Expr::SetComp(ast::ExprSetComp {
|
||||
elt,
|
||||
generators,
|
||||
range: _,
|
||||
}) => {
|
||||
for comprehension in generators {
|
||||
self.visit_comprehension(comprehension);
|
||||
}
|
||||
|
@ -262,10 +279,11 @@ where
|
|||
self.nested = false;
|
||||
}
|
||||
}
|
||||
ExprKind::DictComp(ast::ExprDictComp {
|
||||
Expr::DictComp(ast::ExprDictComp {
|
||||
key,
|
||||
value,
|
||||
generators,
|
||||
range: _,
|
||||
}) => {
|
||||
for comprehension in generators {
|
||||
self.visit_comprehension(comprehension);
|
||||
|
@ -308,10 +326,10 @@ pub(crate) fn reuse_of_groupby_generator(
|
|||
body: &[Stmt],
|
||||
iter: &Expr,
|
||||
) {
|
||||
let ExprKind::Call(ast::ExprCall { func, .. }) = &iter.node else {
|
||||
let Expr::Call(ast::ExprCall { func, .. }) = &iter else {
|
||||
return;
|
||||
};
|
||||
let ExprKind::Tuple(ast::ExprTuple { elts, .. }) = &target.node else {
|
||||
let Expr::Tuple(ast::ExprTuple { elts, .. }) = target else {
|
||||
// Ignore any `groupby()` invocation that isn't unpacked
|
||||
return;
|
||||
};
|
||||
|
@ -319,7 +337,7 @@ pub(crate) fn reuse_of_groupby_generator(
|
|||
return;
|
||||
}
|
||||
// We have an invocation of groupby which is a simple unpacking
|
||||
let ExprKind::Name(ast::ExprName { id: group_name, .. }) = &elts[1].node else {
|
||||
let Expr::Name(ast::ExprName { id: group_name, .. }) = &elts[1] else {
|
||||
return;
|
||||
};
|
||||
// Check if the function call is `itertools.groupby`
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use ruff_text_size::TextRange;
|
||||
use rustpython_parser::ast::{self, Constant, Expr, ExprContext, ExprKind, Stmt, StmtKind};
|
||||
use rustpython_parser::ast::{self, Constant, Expr, ExprContext, Ranged, Stmt};
|
||||
|
||||
use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic, Edit, Fix};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
|
@ -28,21 +28,17 @@ impl AlwaysAutofixableViolation for SetAttrWithConstant {
|
|||
}
|
||||
|
||||
fn assignment(obj: &Expr, name: &str, value: &Expr, stylist: &Stylist) -> String {
|
||||
let stmt = Stmt::new(
|
||||
TextRange::default(),
|
||||
StmtKind::Assign(ast::StmtAssign {
|
||||
targets: vec![Expr::new(
|
||||
TextRange::default(),
|
||||
ExprKind::Attribute(ast::ExprAttribute {
|
||||
let stmt = Stmt::Assign(ast::StmtAssign {
|
||||
targets: vec![Expr::Attribute(ast::ExprAttribute {
|
||||
value: Box::new(obj.clone()),
|
||||
attr: name.into(),
|
||||
ctx: ExprContext::Store,
|
||||
}),
|
||||
)],
|
||||
range: TextRange::default(),
|
||||
})],
|
||||
value: Box::new(value.clone()),
|
||||
type_comment: None,
|
||||
}),
|
||||
);
|
||||
range: TextRange::default(),
|
||||
});
|
||||
unparse_stmt(&stmt, stylist)
|
||||
}
|
||||
|
||||
|
@ -53,7 +49,7 @@ pub(crate) fn setattr_with_constant(
|
|||
func: &Expr,
|
||||
args: &[Expr],
|
||||
) {
|
||||
let ExprKind::Name(ast::ExprName { id, .. }) = &func.node else {
|
||||
let Expr::Name(ast::ExprName { id, .. }) = func else {
|
||||
return;
|
||||
};
|
||||
if id != "setattr" {
|
||||
|
@ -62,10 +58,10 @@ pub(crate) fn setattr_with_constant(
|
|||
let [obj, name, value] = args else {
|
||||
return;
|
||||
};
|
||||
let ExprKind::Constant(ast::ExprConstant {
|
||||
let Expr::Constant(ast::ExprConstant {
|
||||
value: Constant::Str(name),
|
||||
..
|
||||
} )= &name.node else {
|
||||
} )= name else {
|
||||
return;
|
||||
};
|
||||
if !is_identifier(name) {
|
||||
|
@ -76,8 +72,12 @@ pub(crate) fn setattr_with_constant(
|
|||
}
|
||||
// We can only replace a `setattr` call (which is an `Expr`) with an assignment
|
||||
// (which is a `Stmt`) if the `Expr` is already being used as a `Stmt`
|
||||
// (i.e., it's directly within an `StmtKind::Expr`).
|
||||
if let StmtKind::Expr(ast::StmtExpr { value: child }) = &checker.ctx.stmt().node {
|
||||
// (i.e., it's directly within an `Stmt::Expr`).
|
||||
if let Stmt::Expr(ast::StmtExpr {
|
||||
value: child,
|
||||
range: _,
|
||||
}) = &checker.ctx.stmt()
|
||||
{
|
||||
if expr == child.as_ref() {
|
||||
let mut diagnostic = Diagnostic::new(SetAttrWithConstant, expr.range());
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
//! by the unpacked sequence, and this change of ordering can surprise and
|
||||
//! mislead readers.
|
||||
|
||||
use rustpython_parser::ast::{Expr, ExprKind, Keyword};
|
||||
use rustpython_parser::ast::{Expr, Keyword, Ranged};
|
||||
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
|
@ -34,7 +34,7 @@ pub(crate) fn star_arg_unpacking_after_keyword_arg(
|
|||
return;
|
||||
};
|
||||
for arg in args {
|
||||
let ExprKind::Starred (_) = arg.node else {
|
||||
let Expr::Starred (_) = arg else {
|
||||
continue;
|
||||
};
|
||||
if arg.start() <= keyword.start() {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use itertools::Itertools;
|
||||
use rustpython_parser::ast::{self, Constant, Expr, ExprKind};
|
||||
use rustpython_parser::ast::{self, Constant, Expr, Ranged};
|
||||
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
|
@ -23,7 +23,7 @@ pub(crate) fn strip_with_multi_characters(
|
|||
func: &Expr,
|
||||
args: &[Expr],
|
||||
) {
|
||||
let ExprKind::Attribute(ast::ExprAttribute { attr, .. }) = &func.node else {
|
||||
let Expr::Attribute(ast::ExprAttribute { attr, .. }) = func else {
|
||||
return;
|
||||
};
|
||||
if !matches!(attr.as_str(), "strip" | "lstrip" | "rstrip") {
|
||||
|
@ -33,10 +33,10 @@ pub(crate) fn strip_with_multi_characters(
|
|||
return;
|
||||
}
|
||||
|
||||
let ExprKind::Constant(ast::ExprConstant {
|
||||
let Expr::Constant(ast::ExprConstant {
|
||||
value: Constant::Str(value),
|
||||
..
|
||||
} )= &args[0].node else {
|
||||
} )= &args[0] else {
|
||||
return;
|
||||
};
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
//! n += 1
|
||||
//! ```
|
||||
|
||||
use rustpython_parser::ast::{self, Expr, ExprKind, Unaryop};
|
||||
use rustpython_parser::ast::{self, Expr, Ranged, Unaryop};
|
||||
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
|
@ -38,13 +38,13 @@ impl Violation for UnaryPrefixIncrement {
|
|||
pub(crate) fn unary_prefix_increment(
|
||||
checker: &mut Checker,
|
||||
expr: &Expr,
|
||||
op: &Unaryop,
|
||||
op: Unaryop,
|
||||
operand: &Expr,
|
||||
) {
|
||||
if !matches!(op, Unaryop::UAdd) {
|
||||
return;
|
||||
}
|
||||
let ExprKind::UnaryOp(ast::ExprUnaryOp { op, .. })= &operand.node else {
|
||||
let Expr::UnaryOp(ast::ExprUnaryOp { op, .. })= operand else {
|
||||
return;
|
||||
};
|
||||
if !matches!(op, Unaryop::UAdd) {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use rustpython_parser::ast::{self, Expr, ExprKind, Stmt};
|
||||
use rustpython_parser::ast::{self, Expr, Ranged, Stmt};
|
||||
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
|
@ -43,16 +43,16 @@ pub(crate) fn unintentional_type_annotation(
|
|||
if value.is_some() {
|
||||
return;
|
||||
}
|
||||
match &target.node {
|
||||
ExprKind::Subscript(ast::ExprSubscript { value, .. }) => {
|
||||
if matches!(&value.node, ExprKind::Name(_)) {
|
||||
match target {
|
||||
Expr::Subscript(ast::ExprSubscript { value, .. }) => {
|
||||
if value.is_name_expr() {
|
||||
checker
|
||||
.diagnostics
|
||||
.push(Diagnostic::new(UnintentionalTypeAnnotation, stmt.range()));
|
||||
}
|
||||
}
|
||||
ExprKind::Attribute(ast::ExprAttribute { value, .. }) => {
|
||||
if let ExprKind::Name(ast::ExprName { id, .. }) = &value.node {
|
||||
Expr::Attribute(ast::ExprAttribute { value, .. }) => {
|
||||
if let Expr::Name(ast::ExprName { id, .. }) = value.as_ref() {
|
||||
if id != "self" {
|
||||
checker
|
||||
.diagnostics
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use rustpython_parser::ast::{self, Constant, Expr, ExprKind};
|
||||
use rustpython_parser::ast::{self, Constant, Expr, Ranged};
|
||||
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
|
@ -25,7 +25,7 @@ pub(crate) fn unreliable_callable_check(
|
|||
func: &Expr,
|
||||
args: &[Expr],
|
||||
) {
|
||||
let ExprKind::Name(ast::ExprName { id, .. }) = &func.node else {
|
||||
let Expr::Name(ast::ExprName { id, .. }) = func else {
|
||||
return;
|
||||
};
|
||||
if id != "getattr" && id != "hasattr" {
|
||||
|
@ -34,10 +34,10 @@ pub(crate) fn unreliable_callable_check(
|
|||
if args.len() < 2 {
|
||||
return;
|
||||
};
|
||||
let ExprKind::Constant(ast::ExprConstant {
|
||||
let Expr::Constant(ast::ExprConstant {
|
||||
value: Constant::Str(s),
|
||||
..
|
||||
}) = &args[1].node else
|
||||
}) = &args[1] else
|
||||
{
|
||||
return;
|
||||
};
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
//! ```
|
||||
|
||||
use rustc_hash::FxHashMap;
|
||||
use rustpython_parser::ast::{self, Expr, ExprKind, Stmt};
|
||||
use rustpython_parser::ast::{self, Expr, Ranged, Stmt};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use ruff_diagnostics::{AutofixKind, Diagnostic, Edit, Fix, Violation};
|
||||
|
@ -74,7 +74,7 @@ impl Violation for UnusedLoopControlVariable {
|
|||
}
|
||||
}
|
||||
|
||||
/// Identify all `ExprKind::Name` nodes in an AST.
|
||||
/// Identify all `Expr::Name` nodes in an AST.
|
||||
struct NameFinder<'a> {
|
||||
/// A map from identifier to defining expression.
|
||||
names: FxHashMap<&'a str, &'a Expr>,
|
||||
|
@ -93,7 +93,7 @@ where
|
|||
'b: 'a,
|
||||
{
|
||||
fn visit_expr(&mut self, expr: &'a Expr) {
|
||||
if let ExprKind::Name(ast::ExprName { id, .. }) = &expr.node {
|
||||
if let Expr::Name(ast::ExprName { id, .. }) = expr {
|
||||
self.names.insert(id, expr);
|
||||
}
|
||||
visitor::walk_expr(self, expr);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use rustpython_parser::ast::{Expr, ExprKind};
|
||||
use rustpython_parser::ast::{Expr, Ranged};
|
||||
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
|
@ -20,7 +20,7 @@ impl Violation for UselessComparison {
|
|||
|
||||
/// B015
|
||||
pub(crate) fn useless_comparison(checker: &mut Checker, expr: &Expr) {
|
||||
if matches!(expr.node, ExprKind::Compare(_)) {
|
||||
if matches!(expr, Expr::Compare(_)) {
|
||||
checker
|
||||
.diagnostics
|
||||
.push(Diagnostic::new(UselessComparison, expr.range()));
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use rustpython_parser::ast::Expr;
|
||||
use rustpython_parser::ast::{Expr, Ranged};
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use rustpython_parser::ast::{self, Constant, Expr, ExprKind};
|
||||
use rustpython_parser::ast::{self, Constant, Expr, Ranged};
|
||||
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
|
@ -36,15 +36,15 @@ impl Violation for UselessExpression {
|
|||
/// B018
|
||||
pub(crate) fn useless_expression(checker: &mut Checker, value: &Expr) {
|
||||
// Ignore comparisons, as they're handled by `useless_comparison`.
|
||||
if matches!(value.node, ExprKind::Compare(_)) {
|
||||
if matches!(value, Expr::Compare(_)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Ignore strings, to avoid false positives with docstrings.
|
||||
if matches!(
|
||||
value.node,
|
||||
ExprKind::JoinedStr(_)
|
||||
| ExprKind::Constant(ast::ExprConstant {
|
||||
value,
|
||||
Expr::JoinedStr(_)
|
||||
| Expr::Constant(ast::ExprConstant {
|
||||
value: Constant::Str(..) | Constant::Ellipsis,
|
||||
..
|
||||
})
|
||||
|
@ -56,7 +56,7 @@ pub(crate) fn useless_expression(checker: &mut Checker, value: &Expr) {
|
|||
if contains_effect(value, |id| checker.ctx.is_builtin(id)) {
|
||||
// Flag attributes as useless expressions, even if they're attached to calls or other
|
||||
// expressions.
|
||||
if matches!(value.node, ExprKind::Attribute(_)) {
|
||||
if matches!(value, Expr::Attribute(_)) {
|
||||
checker.diagnostics.push(Diagnostic::new(
|
||||
UselessExpression {
|
||||
kind: Kind::Attribute,
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use rustpython_parser::ast::{self, Expr, ExprKind, Keyword};
|
||||
use rustpython_parser::ast::{self, Expr, Keyword, Ranged};
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
|
@ -21,16 +21,12 @@ pub(crate) fn zip_without_explicit_strict(
|
|||
func: &Expr,
|
||||
kwargs: &[Keyword],
|
||||
) {
|
||||
if let ExprKind::Name(ast::ExprName { id, .. }) = &func.node {
|
||||
if let Expr::Name(ast::ExprName { id, .. }) = func {
|
||||
if id == "zip"
|
||||
&& checker.ctx.is_builtin("zip")
|
||||
&& !kwargs.iter().any(|keyword| {
|
||||
keyword
|
||||
.node
|
||||
.arg
|
||||
.as_ref()
|
||||
.map_or(false, |name| name == "strict")
|
||||
})
|
||||
&& !kwargs
|
||||
.iter()
|
||||
.any(|keyword| keyword.arg.as_ref().map_or(false, |name| name == "strict"))
|
||||
{
|
||||
checker
|
||||
.diagnostics
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
use rustpython_parser::ast::Attributed;
|
||||
|
||||
use ruff_diagnostics::Diagnostic;
|
||||
use ruff_diagnostics::Violation;
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
use ruff_python_stdlib::builtins::BUILTINS;
|
||||
use rustpython_parser::ast::Ranged;
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
|
||||
|
@ -172,11 +171,10 @@ fn shadows_builtin(name: &str, ignorelist: &[String]) -> bool {
|
|||
}
|
||||
|
||||
/// A001
|
||||
pub(crate) fn builtin_variable_shadowing<T>(
|
||||
checker: &mut Checker,
|
||||
name: &str,
|
||||
attributed: &Attributed<T>,
|
||||
) {
|
||||
pub(crate) fn builtin_variable_shadowing<T>(checker: &mut Checker, name: &str, attributed: &T)
|
||||
where
|
||||
T: Ranged,
|
||||
{
|
||||
if shadows_builtin(name, &checker.settings.flake8_builtins.builtins_ignorelist) {
|
||||
checker.diagnostics.push(Diagnostic::new(
|
||||
BuiltinVariableShadowing {
|
||||
|
@ -188,11 +186,10 @@ pub(crate) fn builtin_variable_shadowing<T>(
|
|||
}
|
||||
|
||||
/// A002
|
||||
pub(crate) fn builtin_argument_shadowing<T>(
|
||||
checker: &mut Checker,
|
||||
name: &str,
|
||||
attributed: &Attributed<T>,
|
||||
) {
|
||||
pub(crate) fn builtin_argument_shadowing<T>(checker: &mut Checker, name: &str, attributed: &T)
|
||||
where
|
||||
T: Ranged,
|
||||
{
|
||||
if shadows_builtin(name, &checker.settings.flake8_builtins.builtins_ignorelist) {
|
||||
checker.diagnostics.push(Diagnostic::new(
|
||||
BuiltinArgumentShadowing {
|
||||
|
@ -204,11 +201,10 @@ pub(crate) fn builtin_argument_shadowing<T>(
|
|||
}
|
||||
|
||||
/// A003
|
||||
pub(crate) fn builtin_attribute_shadowing<T>(
|
||||
checker: &mut Checker,
|
||||
name: &str,
|
||||
attributed: &Attributed<T>,
|
||||
) {
|
||||
pub(crate) fn builtin_attribute_shadowing<T>(checker: &mut Checker, name: &str, attributed: &T)
|
||||
where
|
||||
T: Ranged,
|
||||
{
|
||||
if shadows_builtin(name, &checker.settings.flake8_builtins.builtins_ignorelist) {
|
||||
checker.diagnostics.push(Diagnostic::new(
|
||||
BuiltinAttributeShadowing {
|
||||
|
|
|
@ -7,6 +7,7 @@ use libcst_native::{
|
|||
ParenthesizedWhitespace, RightCurlyBrace, RightParen, RightSquareBracket, Set, SetComp,
|
||||
SimpleString, SimpleWhitespace, TrailingWhitespace, Tuple,
|
||||
};
|
||||
use rustpython_parser::ast::Ranged;
|
||||
|
||||
use ruff_diagnostics::{Edit, Fix};
|
||||
use ruff_python_ast::source_code::{Locator, Stylist};
|
||||
|
@ -115,11 +116,9 @@ pub(crate) fn fix_unnecessary_generator_set(
|
|||
|
||||
// If the expression is embedded in an f-string, surround it with spaces to avoid
|
||||
// syntax errors.
|
||||
if let Some(parent_element) = parent {
|
||||
if let &rustpython_parser::ast::ExprKind::FormattedValue(_) = &parent_element.node {
|
||||
if let Some(rustpython_parser::ast::Expr::FormattedValue(_)) = parent {
|
||||
content = format!(" {content} ");
|
||||
}
|
||||
}
|
||||
|
||||
Ok(Edit::range_replacement(content, expr.range()))
|
||||
}
|
||||
|
@ -185,11 +184,9 @@ pub(crate) fn fix_unnecessary_generator_dict(
|
|||
|
||||
// If the expression is embedded in an f-string, surround it with spaces to avoid
|
||||
// syntax errors.
|
||||
if let Some(parent_element) = parent {
|
||||
if let &rustpython_parser::ast::ExprKind::FormattedValue(_) = &parent_element.node {
|
||||
if let Some(rustpython_parser::ast::Expr::FormattedValue(_)) = parent {
|
||||
content = format!(" {content} ");
|
||||
}
|
||||
}
|
||||
|
||||
Ok(Edit::range_replacement(content, expr.range()))
|
||||
}
|
||||
|
@ -1100,12 +1097,10 @@ pub(crate) fn fix_unnecessary_map(
|
|||
// If the expression is embedded in an f-string, surround it with spaces to avoid
|
||||
// syntax errors.
|
||||
if kind == "set" || kind == "dict" {
|
||||
if let Some(parent_element) = parent {
|
||||
if let &rustpython_parser::ast::ExprKind::FormattedValue(_) = &parent_element.node {
|
||||
if let Some(rustpython_parser::ast::Expr::FormattedValue(_)) = parent {
|
||||
content = format!(" {content} ");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(Edit::range_replacement(content, expr.range()))
|
||||
} else {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use rustpython_parser::ast::{self, Expr, ExprKind, Keyword};
|
||||
use rustpython_parser::ast::{self, Expr, Keyword};
|
||||
|
||||
pub(crate) fn expr_name(func: &Expr) -> Option<&str> {
|
||||
if let ExprKind::Name(ast::ExprName { id, .. }) = &func.node {
|
||||
if let Expr::Name(ast::ExprName { id, .. }) = func {
|
||||
Some(id)
|
||||
} else {
|
||||
None
|
||||
|
@ -13,7 +13,7 @@ pub(crate) fn exactly_one_argument_with_matching_function<'a>(
|
|||
func: &Expr,
|
||||
args: &'a [Expr],
|
||||
keywords: &[Keyword],
|
||||
) -> Option<&'a ExprKind> {
|
||||
) -> Option<&'a Expr> {
|
||||
if !keywords.is_empty() {
|
||||
return None;
|
||||
}
|
||||
|
@ -23,16 +23,16 @@ pub(crate) fn exactly_one_argument_with_matching_function<'a>(
|
|||
if expr_name(func)? != name {
|
||||
return None;
|
||||
}
|
||||
Some(&args[0].node)
|
||||
Some(&args[0])
|
||||
}
|
||||
|
||||
pub(crate) fn first_argument_with_matching_function<'a>(
|
||||
name: &str,
|
||||
func: &Expr,
|
||||
args: &'a [Expr],
|
||||
) -> Option<&'a ExprKind> {
|
||||
) -> Option<&'a Expr> {
|
||||
if expr_name(func)? == name {
|
||||
Some(&args.first()?.node)
|
||||
Some(args.first()?)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use rustpython_parser::ast::{self, Expr, ExprKind};
|
||||
use rustpython_parser::ast::{self, Expr, Ranged};
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::registry::AsRule;
|
||||
|
@ -65,7 +65,7 @@ pub(crate) fn unnecessary_call_around_sorted(
|
|||
let Some(arg) = args.first() else {
|
||||
return;
|
||||
};
|
||||
let ExprKind::Call(ast::ExprCall { func, .. }) = &arg.node else {
|
||||
let Expr::Call(ast::ExprCall { func, .. }) = arg else {
|
||||
return;
|
||||
};
|
||||
let Some(inner) = helpers::expr_name(func) else {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use rustpython_parser::ast::{Expr, Keyword};
|
||||
use rustpython_parser::ast::{Expr, Keyword, Ranged};
|
||||
|
||||
use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
|
@ -70,7 +70,7 @@ pub(crate) fn unnecessary_collection_call(
|
|||
"dict"
|
||||
if keywords.is_empty()
|
||||
|| (!settings.allow_dict_calls_with_keyword_arguments
|
||||
&& keywords.iter().all(|kw| kw.node.arg.is_some())) =>
|
||||
&& keywords.iter().all(|kw| kw.arg.is_some())) =>
|
||||
{
|
||||
// `dict()` or `dict(a=1)` (as opposed to `dict(**a)`)
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use rustpython_parser::ast::{self, Comprehension, Expr, ExprKind};
|
||||
use rustpython_parser::ast::{self, Comprehension, Expr, Ranged};
|
||||
|
||||
use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
|
@ -50,10 +50,10 @@ impl AlwaysAutofixableViolation for UnnecessaryComprehension {
|
|||
|
||||
/// Add diagnostic for C416 based on the expression node id.
|
||||
fn add_diagnostic(checker: &mut Checker, expr: &Expr) {
|
||||
let id = match &expr.node {
|
||||
ExprKind::ListComp(_) => "list",
|
||||
ExprKind::SetComp(_) => "set",
|
||||
ExprKind::DictComp(_) => "dict",
|
||||
let id = match expr {
|
||||
Expr::ListComp(_) => "list",
|
||||
Expr::SetComp(_) => "set",
|
||||
Expr::DictComp(_) => "dict",
|
||||
_ => return,
|
||||
};
|
||||
if !checker.ctx.is_builtin(id) {
|
||||
|
@ -95,7 +95,7 @@ pub(crate) fn unnecessary_dict_comprehension(
|
|||
let Some(value_id) = helpers::expr_name(value) else {
|
||||
return;
|
||||
};
|
||||
let ExprKind::Tuple(ast::ExprTuple { elts, .. }) = &generator.target.node else {
|
||||
let Expr::Tuple(ast::ExprTuple { elts, .. }) = &generator.target else {
|
||||
return;
|
||||
};
|
||||
if elts.len() != 2 {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use rustpython_parser::ast::{self, Expr, ExprKind, Keyword};
|
||||
use rustpython_parser::ast::{self, Expr, Keyword, Ranged};
|
||||
|
||||
use ruff_diagnostics::Violation;
|
||||
use ruff_diagnostics::{AutofixKind, Diagnostic};
|
||||
|
@ -66,11 +66,11 @@ pub(crate) fn unnecessary_comprehension_any_all(
|
|||
if !keywords.is_empty() {
|
||||
return;
|
||||
}
|
||||
let ExprKind::Name(ast::ExprName { id, .. } )= &func.node else {
|
||||
let Expr::Name(ast::ExprName { id, .. } )= func else {
|
||||
return;
|
||||
};
|
||||
if (matches!(id.as_str(), "all" | "any")) && args.len() == 1 {
|
||||
let (ExprKind::ListComp(ast::ExprListComp { elt, .. } )| ExprKind::SetComp(ast::ExprSetComp { elt, .. })) = &args[0].node else {
|
||||
let (Expr::ListComp(ast::ExprListComp { elt, .. } )| Expr::SetComp(ast::ExprSetComp { elt, .. })) = &args[0] else {
|
||||
return;
|
||||
};
|
||||
if is_async_generator(elt) {
|
||||
|
@ -91,5 +91,5 @@ pub(crate) fn unnecessary_comprehension_any_all(
|
|||
|
||||
/// Return `true` if the `Expr` contains an `await` expression.
|
||||
fn is_async_generator(expr: &Expr) -> bool {
|
||||
any_over_expr(expr, &|expr| matches!(expr.node, ExprKind::Await(_)))
|
||||
any_over_expr(expr, &|expr| matches!(expr, Expr::Await(_)))
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use rustpython_parser::ast::{self, Expr, ExprKind};
|
||||
use rustpython_parser::ast::{self, Expr, Ranged};
|
||||
|
||||
use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
|
@ -84,7 +84,7 @@ pub(crate) fn unnecessary_double_cast_or_process(
|
|||
let Some(arg) = args.first() else {
|
||||
return;
|
||||
};
|
||||
let ExprKind::Call(ast::ExprCall { func, ..} )= &arg.node else {
|
||||
let Expr::Call(ast::ExprCall { func, ..} )= arg else {
|
||||
return;
|
||||
};
|
||||
let Some(inner) = helpers::expr_name(func) else {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use rustpython_parser::ast::{self, Expr, ExprKind, Keyword};
|
||||
use rustpython_parser::ast::{self, Expr, Keyword, Ranged};
|
||||
|
||||
use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
|
@ -53,9 +53,9 @@ pub(crate) fn unnecessary_generator_dict(
|
|||
let Some(argument) = helpers::exactly_one_argument_with_matching_function("dict", func, args, keywords) else {
|
||||
return;
|
||||
};
|
||||
if let ExprKind::GeneratorExp(ast::ExprGeneratorExp { elt, .. }) = argument {
|
||||
match &elt.node {
|
||||
ExprKind::Tuple(ast::ExprTuple { elts, .. }) if elts.len() == 2 => {
|
||||
if let Expr::GeneratorExp(ast::ExprGeneratorExp { elt, .. }) = argument {
|
||||
match elt.as_ref() {
|
||||
Expr::Tuple(ast::ExprTuple { elts, .. }) if elts.len() == 2 => {
|
||||
let mut diagnostic = Diagnostic::new(UnnecessaryGeneratorDict, expr.range());
|
||||
if checker.patch(diagnostic.kind.rule()) {
|
||||
#[allow(deprecated)]
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use rustpython_parser::ast::{Expr, ExprKind, Keyword};
|
||||
use rustpython_parser::ast::{Expr, Keyword, Ranged};
|
||||
|
||||
use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
|
@ -55,7 +55,7 @@ pub(crate) fn unnecessary_generator_list(
|
|||
if !checker.ctx.is_builtin("list") {
|
||||
return;
|
||||
}
|
||||
if let ExprKind::GeneratorExp(_) = argument {
|
||||
if let Expr::GeneratorExp(_) = argument {
|
||||
let mut diagnostic = Diagnostic::new(UnnecessaryGeneratorList, expr.range());
|
||||
if checker.patch(diagnostic.kind.rule()) {
|
||||
#[allow(deprecated)]
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use rustpython_parser::ast::{Expr, ExprKind, Keyword};
|
||||
use rustpython_parser::ast::{Expr, Keyword, Ranged};
|
||||
|
||||
use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
|
@ -56,7 +56,7 @@ pub(crate) fn unnecessary_generator_set(
|
|||
if !checker.ctx.is_builtin("set") {
|
||||
return;
|
||||
}
|
||||
if let ExprKind::GeneratorExp(_) = argument {
|
||||
if let Expr::GeneratorExp(_) = argument {
|
||||
let mut diagnostic = Diagnostic::new(UnnecessaryGeneratorSet, expr.range());
|
||||
if checker.patch(diagnostic.kind.rule()) {
|
||||
#[allow(deprecated)]
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use rustpython_parser::ast::Expr;
|
||||
use rustpython_parser::ast::{Expr, Ranged};
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::registry::AsRule;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use rustpython_parser::ast::{self, Expr, ExprKind, Keyword};
|
||||
use rustpython_parser::ast::{self, Expr, Keyword, Ranged};
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::registry::AsRule;
|
||||
|
@ -52,10 +52,10 @@ pub(crate) fn unnecessary_list_comprehension_dict(
|
|||
if !checker.ctx.is_builtin("dict") {
|
||||
return;
|
||||
}
|
||||
let ExprKind::ListComp(ast::ExprListComp { elt, .. }) = &argument else {
|
||||
let Expr::ListComp(ast::ExprListComp { elt, .. }) = argument else {
|
||||
return;
|
||||
};
|
||||
let ExprKind::Tuple(ast::ExprTuple { elts, .. }) = &elt.node else {
|
||||
let Expr::Tuple(ast::ExprTuple { elts, .. }) = elt.as_ref() else {
|
||||
return;
|
||||
};
|
||||
if elts.len() != 2 {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use rustpython_parser::ast::{Expr, Keyword};
|
||||
use rustpython_parser::ast::{Expr, Keyword, Ranged};
|
||||
|
||||
use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use rustpython_parser::ast::{self, Expr, ExprKind, Keyword};
|
||||
use rustpython_parser::ast::{self, Expr, Keyword, Ranged};
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::registry::AsRule;
|
||||
|
@ -60,14 +60,15 @@ pub(crate) fn unnecessary_literal_dict(
|
|||
return;
|
||||
}
|
||||
let (kind, elts) = match argument {
|
||||
ExprKind::Tuple(ast::ExprTuple { elts, .. }) => ("tuple", elts),
|
||||
ExprKind::List(ast::ExprList { elts, .. }) => ("list", elts),
|
||||
Expr::Tuple(ast::ExprTuple { elts, .. }) => ("tuple", elts),
|
||||
Expr::List(ast::ExprList { elts, .. }) => ("list", elts),
|
||||
_ => return,
|
||||
};
|
||||
// Accept `dict((1, 2), ...))` `dict([(1, 2), ...])`.
|
||||
if !elts.iter().all(
|
||||
|elt| matches!(&elt.node, ExprKind::Tuple(ast::ExprTuple { elts, .. } )if elts.len() == 2),
|
||||
) {
|
||||
if !elts
|
||||
.iter()
|
||||
.all(|elt| matches!(&elt, Expr::Tuple(ast::ExprTuple { elts, .. } )if elts.len() == 2))
|
||||
{
|
||||
return;
|
||||
}
|
||||
let mut diagnostic = Diagnostic::new(
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use rustpython_parser::ast::{Expr, ExprKind, Keyword};
|
||||
use rustpython_parser::ast::{Expr, Keyword, Ranged};
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::registry::AsRule;
|
||||
|
@ -61,8 +61,8 @@ pub(crate) fn unnecessary_literal_set(
|
|||
return;
|
||||
}
|
||||
let kind = match argument {
|
||||
ExprKind::List(_) => "list",
|
||||
ExprKind::Tuple(_) => "tuple",
|
||||
Expr::List(_) => "list",
|
||||
Expr::Tuple(_) => "tuple",
|
||||
_ => return,
|
||||
};
|
||||
let mut diagnostic = Diagnostic::new(
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use rustpython_parser::ast::{Expr, ExprKind, Keyword};
|
||||
use rustpython_parser::ast::{Expr, Keyword, Ranged};
|
||||
use std::fmt;
|
||||
|
||||
use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic};
|
||||
|
@ -79,8 +79,8 @@ pub(crate) fn unnecessary_literal_within_dict_call(
|
|||
return;
|
||||
}
|
||||
let argument_kind = match argument {
|
||||
ExprKind::DictComp(_) => DictKind::Comprehension,
|
||||
ExprKind::Dict(_) => DictKind::Literal,
|
||||
Expr::DictComp(_) => DictKind::Comprehension,
|
||||
Expr::Dict(_) => DictKind::Literal,
|
||||
_ => return,
|
||||
};
|
||||
let mut diagnostic = Diagnostic::new(
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use rustpython_parser::ast::{Expr, ExprKind, Keyword};
|
||||
use rustpython_parser::ast::{Expr, Keyword, Ranged};
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::registry::AsRule;
|
||||
|
@ -82,8 +82,8 @@ pub(crate) fn unnecessary_literal_within_list_call(
|
|||
return;
|
||||
}
|
||||
let argument_kind = match argument {
|
||||
ExprKind::Tuple(_) => "tuple",
|
||||
ExprKind::List(_) => "list",
|
||||
Expr::Tuple(_) => "tuple",
|
||||
Expr::List(_) => "list",
|
||||
_ => return,
|
||||
};
|
||||
let mut diagnostic = Diagnostic::new(
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use rustpython_parser::ast::{Expr, ExprKind, Keyword};
|
||||
use rustpython_parser::ast::{Expr, Keyword, Ranged};
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::registry::AsRule;
|
||||
|
@ -83,8 +83,8 @@ pub(crate) fn unnecessary_literal_within_tuple_call(
|
|||
return;
|
||||
}
|
||||
let argument_kind = match argument {
|
||||
ExprKind::Tuple(_) => "tuple",
|
||||
ExprKind::List(_) => "list",
|
||||
Expr::Tuple(_) => "tuple",
|
||||
Expr::List(_) => "list",
|
||||
_ => return,
|
||||
};
|
||||
let mut diagnostic = Diagnostic::new(
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use ruff_text_size::TextRange;
|
||||
use rustpython_parser::ast::{self, Expr, ExprKind};
|
||||
use rustpython_parser::ast::{self, Expr, Ranged};
|
||||
|
||||
use ruff_diagnostics::Diagnostic;
|
||||
use ruff_diagnostics::{AutofixKind, Violation};
|
||||
|
@ -93,17 +93,15 @@ pub(crate) fn unnecessary_map(
|
|||
}
|
||||
|
||||
// Exclude the parent if already matched by other arms
|
||||
if let Some(parent) = parent {
|
||||
if let ExprKind::Call(ast::ExprCall { func: f, .. }) = &parent.node {
|
||||
if let Some(Expr::Call(ast::ExprCall { func: f, .. })) = parent {
|
||||
if let Some(id_parent) = helpers::expr_name(f) {
|
||||
if id_parent == "dict" || id_parent == "set" || id_parent == "list" {
|
||||
return;
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
if args.len() == 2 && matches!(&args[0].node, ExprKind::Lambda(_)) {
|
||||
if args.len() == 2 && matches!(&args[0], Expr::Lambda(_)) {
|
||||
let mut diagnostic = create_diagnostic("generator", expr.range());
|
||||
if checker.patch(diagnostic.kind.rule()) {
|
||||
#[allow(deprecated)]
|
||||
|
@ -125,15 +123,14 @@ pub(crate) fn unnecessary_map(
|
|||
return;
|
||||
}
|
||||
|
||||
if let Some(arg) = args.first() {
|
||||
if let ExprKind::Call(ast::ExprCall { func, args, .. }) = &arg.node {
|
||||
if let Some(Expr::Call(ast::ExprCall { func, args, .. })) = args.first() {
|
||||
if args.len() != 2 {
|
||||
return;
|
||||
}
|
||||
let Some(argument) = helpers::first_argument_with_matching_function("map", func, args) else {
|
||||
return;
|
||||
};
|
||||
if let ExprKind::Lambda(_) = argument {
|
||||
if let Expr::Lambda(_) = argument {
|
||||
let mut diagnostic = create_diagnostic(id, expr.range());
|
||||
if checker.patch(diagnostic.kind.rule()) {
|
||||
#[allow(deprecated)]
|
||||
|
@ -151,19 +148,18 @@ pub(crate) fn unnecessary_map(
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
"dict" => {
|
||||
if !checker.ctx.is_builtin(id) {
|
||||
return;
|
||||
}
|
||||
|
||||
if args.len() == 1 {
|
||||
if let ExprKind::Call(ast::ExprCall { func, args, .. }) = &args[0].node {
|
||||
if let Expr::Call(ast::ExprCall { func, args, .. }) = &args[0] {
|
||||
let Some(argument) = helpers::first_argument_with_matching_function("map", func, args) else {
|
||||
return;
|
||||
};
|
||||
if let ExprKind::Lambda(ast::ExprLambda { body, .. }) = &argument {
|
||||
if matches!(&body.node, ExprKind::Tuple(ast::ExprTuple { elts, .. }) | ExprKind::List(ast::ExprList { elts, .. } )if elts.len() == 2)
|
||||
if let Expr::Lambda(ast::ExprLambda { body, .. }) = argument {
|
||||
if matches!(body.as_ref(), Expr::Tuple(ast::ExprTuple { elts, .. }) | Expr::List(ast::ExprList { elts, .. } ) if elts.len() == 2)
|
||||
{
|
||||
let mut diagnostic = create_diagnostic(id, expr.range());
|
||||
if checker.patch(diagnostic.kind.rule()) {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use num_bigint::BigInt;
|
||||
use rustpython_parser::ast::{self, Constant, Expr, ExprKind, Unaryop};
|
||||
use rustpython_parser::ast::{self, Constant, Expr, Ranged, Unaryop};
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
|
@ -60,10 +60,10 @@ pub(crate) fn unnecessary_subscript_reversal(
|
|||
if !checker.ctx.is_builtin(id) {
|
||||
return;
|
||||
}
|
||||
let ExprKind::Subscript(ast::ExprSubscript { slice, .. }) = &first_arg.node else {
|
||||
let Expr::Subscript(ast::ExprSubscript { slice, .. }) = first_arg else {
|
||||
return;
|
||||
};
|
||||
let ExprKind::Slice(ast::ExprSlice { lower, upper, step }) = &slice.node else {
|
||||
let Expr::Slice(ast::ExprSlice { lower, upper, step, range: _ }) = slice.as_ref() else {
|
||||
return;
|
||||
};
|
||||
if lower.is_some() || upper.is_some() {
|
||||
|
@ -72,16 +72,17 @@ pub(crate) fn unnecessary_subscript_reversal(
|
|||
let Some(step) = step.as_ref() else {
|
||||
return;
|
||||
};
|
||||
let ExprKind::UnaryOp(ast::ExprUnaryOp {
|
||||
let Expr::UnaryOp(ast::ExprUnaryOp {
|
||||
op: Unaryop::USub,
|
||||
operand,
|
||||
}) = &step.node else {
|
||||
range: _,
|
||||
}) = step.as_ref() else {
|
||||
return;
|
||||
};
|
||||
let ExprKind::Constant(ast::ExprConstant {
|
||||
let Expr::Constant(ast::ExprConstant {
|
||||
value: Constant::Int(val),
|
||||
..
|
||||
}) = &operand.node else {
|
||||
}) = operand.as_ref() else {
|
||||
return;
|
||||
};
|
||||
if *val != BigInt::from(1) {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use ruff_text_size::TextRange;
|
||||
use rustpython_parser::ast::{self, Constant, Expr, ExprKind, Keyword};
|
||||
use rustpython_parser::ast::{self, Constant, Expr, Keyword};
|
||||
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
|
@ -321,10 +321,11 @@ pub(crate) fn call_datetime_strptime_without_zone(
|
|||
}
|
||||
|
||||
// Does the `strptime` call contain a format string with a timezone specifier?
|
||||
if let Some(ExprKind::Constant(ast::ExprConstant {
|
||||
if let Some(Expr::Constant(ast::ExprConstant {
|
||||
value: Constant::Str(format),
|
||||
kind: None,
|
||||
})) = args.get(1).as_ref().map(|arg| &arg.node)
|
||||
range: _,
|
||||
})) = args.get(1).as_ref()
|
||||
{
|
||||
if format.contains("%z") {
|
||||
return;
|
||||
|
@ -339,8 +340,8 @@ pub(crate) fn call_datetime_strptime_without_zone(
|
|||
return;
|
||||
};
|
||||
|
||||
if let ExprKind::Call(ast::ExprCall { keywords, .. }) = &grandparent.node {
|
||||
if let ExprKind::Attribute(ast::ExprAttribute { attr, .. }) = &parent.node {
|
||||
if let Expr::Call(ast::ExprCall { keywords, .. }) = grandparent {
|
||||
if let Expr::Attribute(ast::ExprAttribute { attr, .. }) = parent {
|
||||
let attr = attr.as_str();
|
||||
// Ex) `datetime.strptime(...).astimezone()`
|
||||
if attr == "astimezone" {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use rustpython_parser::ast::{Expr, Stmt};
|
||||
use rustpython_parser::ast::{Expr, Ranged, Stmt};
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::rules::flake8_debugger::types::DebuggerUsingType;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use rustpython_parser::ast::{self, Constant, Expr, ExprKind, Stmt, StmtKind};
|
||||
use rustpython_parser::ast::{self, Constant, Expr, Ranged, Stmt};
|
||||
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
|
@ -56,27 +56,27 @@ pub(crate) fn all_with_model_form(
|
|||
return None;
|
||||
}
|
||||
for element in body.iter() {
|
||||
let StmtKind::ClassDef(ast::StmtClassDef { name, body, .. }) = &element.node else {
|
||||
let Stmt::ClassDef(ast::StmtClassDef { name, body, .. }) = element else {
|
||||
continue;
|
||||
};
|
||||
if name != "Meta" {
|
||||
continue;
|
||||
}
|
||||
for element in body.iter() {
|
||||
let StmtKind::Assign(ast::StmtAssign { targets, value, .. }) = &element.node else {
|
||||
let Stmt::Assign(ast::StmtAssign { targets, value, .. }) = element else {
|
||||
continue;
|
||||
};
|
||||
for target in targets.iter() {
|
||||
let ExprKind::Name(ast::ExprName { id, .. }) = &target.node else {
|
||||
let Expr::Name(ast::ExprName { id, .. }) = target else {
|
||||
continue;
|
||||
};
|
||||
if id != "fields" {
|
||||
continue;
|
||||
}
|
||||
let ExprKind::Constant(ast::ExprConstant { value, .. }) = &value.node else {
|
||||
let Expr::Constant(ast::ExprConstant { value, .. }) = value.as_ref() else {
|
||||
continue;
|
||||
};
|
||||
match &value {
|
||||
match value {
|
||||
Constant::Str(s) => {
|
||||
if s == "__all__" {
|
||||
return Some(Diagnostic::new(DjangoAllWithModelForm, element.range()));
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use rustpython_parser::ast::{self, Expr, ExprKind, Stmt, StmtKind};
|
||||
use rustpython_parser::ast::{self, Expr, Ranged, Stmt};
|
||||
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
|
@ -54,18 +54,18 @@ pub(crate) fn exclude_with_model_form(
|
|||
return None;
|
||||
}
|
||||
for element in body.iter() {
|
||||
let StmtKind::ClassDef(ast::StmtClassDef { name, body, .. }) = &element.node else {
|
||||
let Stmt::ClassDef(ast::StmtClassDef { name, body, .. }) = element else {
|
||||
continue;
|
||||
};
|
||||
if name != "Meta" {
|
||||
continue;
|
||||
}
|
||||
for element in body.iter() {
|
||||
let StmtKind::Assign(ast::StmtAssign { targets, .. }) = &element.node else {
|
||||
let Stmt::Assign(ast::StmtAssign { targets, .. }) = element else {
|
||||
continue;
|
||||
};
|
||||
for target in targets.iter() {
|
||||
let ExprKind::Name(ast::ExprName { id, .. }) = &target.node else {
|
||||
let Expr::Name(ast::ExprName { id, .. }) = target else {
|
||||
continue;
|
||||
};
|
||||
if id == "exclude" {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use rustpython_parser::ast::{self, Expr, ExprKind, Keyword};
|
||||
use rustpython_parser::ast::{self, Expr, Keyword, Ranged};
|
||||
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
|
@ -64,17 +64,14 @@ pub(crate) fn locals_in_render_function(
|
|||
return;
|
||||
}
|
||||
&args[2]
|
||||
} else if let Some(keyword) = keywords.iter().find(|keyword| {
|
||||
keyword
|
||||
.node
|
||||
.arg
|
||||
.as_ref()
|
||||
.map_or(false, |arg| arg == "context")
|
||||
}) {
|
||||
if !is_locals_call(checker, &keyword.node.value) {
|
||||
} else if let Some(keyword) = keywords
|
||||
.iter()
|
||||
.find(|keyword| keyword.arg.as_ref().map_or(false, |arg| arg == "context"))
|
||||
{
|
||||
if !is_locals_call(checker, &keyword.value) {
|
||||
return;
|
||||
}
|
||||
&keyword.node.value
|
||||
&keyword.value
|
||||
} else {
|
||||
return;
|
||||
};
|
||||
|
@ -86,7 +83,7 @@ pub(crate) fn locals_in_render_function(
|
|||
}
|
||||
|
||||
fn is_locals_call(checker: &Checker, expr: &Expr) -> bool {
|
||||
let ExprKind::Call(ast::ExprCall { func, .. }) = &expr.node else {
|
||||
let Expr::Call(ast::ExprCall { func, .. }) = expr else {
|
||||
return false
|
||||
};
|
||||
checker
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use rustpython_parser::ast::{self, Constant, Expr, ExprKind, Stmt, StmtKind};
|
||||
use rustpython_parser::ast::{self, Constant, Expr, Ranged, Stmt};
|
||||
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
|
@ -68,8 +68,8 @@ pub(crate) fn model_without_dunder_str(
|
|||
}
|
||||
|
||||
fn has_dunder_method(body: &[Stmt]) -> bool {
|
||||
body.iter().any(|val| match &val.node {
|
||||
StmtKind::FunctionDef(ast::StmtFunctionDef { name, .. }) => {
|
||||
body.iter().any(|val| match val {
|
||||
Stmt::FunctionDef(ast::StmtFunctionDef { name, .. }) => {
|
||||
if name == "__str__" {
|
||||
return true;
|
||||
}
|
||||
|
@ -94,24 +94,24 @@ fn checker_applies(checker: &Checker, bases: &[Expr], body: &[Stmt]) -> bool {
|
|||
/// Check if class is abstract, in terms of Django model inheritance.
|
||||
fn is_model_abstract(body: &[Stmt]) -> bool {
|
||||
for element in body.iter() {
|
||||
let StmtKind::ClassDef(ast::StmtClassDef {name, body, ..}) = &element.node else {
|
||||
let Stmt::ClassDef(ast::StmtClassDef {name, body, ..}) = element else {
|
||||
continue
|
||||
};
|
||||
if name != "Meta" {
|
||||
continue;
|
||||
}
|
||||
for element in body.iter() {
|
||||
let StmtKind::Assign(ast::StmtAssign {targets, value, ..}) = &element.node else {
|
||||
let Stmt::Assign(ast::StmtAssign {targets, value, ..}) = element else {
|
||||
continue;
|
||||
};
|
||||
for target in targets.iter() {
|
||||
let ExprKind::Name(ast::ExprName {id , ..}) = &target.node else {
|
||||
let Expr::Name(ast::ExprName {id , ..}) = target else {
|
||||
continue;
|
||||
};
|
||||
if id != "abstract" {
|
||||
continue;
|
||||
}
|
||||
let ExprKind::Constant(ast::ExprConstant{value: Constant::Bool(true), ..}) = &value.node else {
|
||||
let Expr::Constant(ast::ExprConstant{value: Constant::Bool(true), ..}) = value.as_ref() else {
|
||||
continue;
|
||||
};
|
||||
return true;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use rustpython_parser::ast::{self, Expr, ExprKind};
|
||||
use rustpython_parser::ast::{self, Expr, Ranged};
|
||||
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
|
@ -58,8 +58,8 @@ where
|
|||
let mut diagnostics = vec![];
|
||||
let mut seen_receiver = false;
|
||||
for (i, decorator) in decorator_list.iter().enumerate() {
|
||||
let is_receiver = match &decorator.node {
|
||||
ExprKind::Call(ast::ExprCall { func, .. }) => resolve_call_path(func)
|
||||
let is_receiver = match decorator {
|
||||
Expr::Call(ast::ExprCall { func, .. }) => resolve_call_path(func)
|
||||
.map_or(false, |call_path| {
|
||||
call_path.as_slice() == ["django", "dispatch", "receiver"]
|
||||
}),
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use rustpython_parser::ast::Constant::Bool;
|
||||
use rustpython_parser::ast::{self, Expr, ExprKind, Stmt, StmtKind};
|
||||
use rustpython_parser::ast::{self, Expr, Ranged, Stmt};
|
||||
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
|
@ -64,7 +64,7 @@ const NOT_NULL_TRUE_FIELDS: [&str; 6] = [
|
|||
pub(crate) fn nullable_model_string_field(checker: &Checker, body: &[Stmt]) -> Vec<Diagnostic> {
|
||||
let mut errors = Vec::new();
|
||||
for statement in body.iter() {
|
||||
let StmtKind::Assign(ast::StmtAssign {value, ..}) = &statement.node else {
|
||||
let Stmt::Assign(ast::StmtAssign {value, ..}) = statement else {
|
||||
continue
|
||||
};
|
||||
if let Some(field_name) = is_nullable_field(checker, value) {
|
||||
|
@ -80,7 +80,7 @@ pub(crate) fn nullable_model_string_field(checker: &Checker, body: &[Stmt]) -> V
|
|||
}
|
||||
|
||||
fn is_nullable_field<'a>(checker: &'a Checker, value: &'a Expr) -> Option<&'a str> {
|
||||
let ExprKind::Call(ast::ExprCall {func, keywords, ..}) = &value.node else {
|
||||
let Expr::Call(ast::ExprCall {func, keywords, ..}) = value else {
|
||||
return None;
|
||||
};
|
||||
|
||||
|
@ -96,10 +96,10 @@ fn is_nullable_field<'a>(checker: &'a Checker, value: &'a Expr) -> Option<&'a st
|
|||
let mut blank_key = false;
|
||||
let mut unique_key = false;
|
||||
for keyword in keywords.iter() {
|
||||
let ExprKind::Constant(ast::ExprConstant {value: Bool(true), ..}) = &keyword.node.value.node else {
|
||||
let Expr::Constant(ast::ExprConstant {value: Bool(true), ..}) = &keyword.value else {
|
||||
continue
|
||||
};
|
||||
let Some(argument) = &keyword.node.arg else {
|
||||
let Some(argument) = &keyword.arg else {
|
||||
continue
|
||||
};
|
||||
match argument.as_str() {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use std::fmt;
|
||||
|
||||
use rustpython_parser::ast::{self, Expr, ExprKind, Stmt, StmtKind};
|
||||
use rustpython_parser::ast::{self, Expr, Ranged, Stmt};
|
||||
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
|
@ -99,10 +99,10 @@ impl fmt::Display for ContentType {
|
|||
}
|
||||
}
|
||||
|
||||
fn get_element_type(checker: &Checker, element: &StmtKind) -> Option<ContentType> {
|
||||
fn get_element_type(checker: &Checker, element: &Stmt) -> Option<ContentType> {
|
||||
match element {
|
||||
StmtKind::Assign(ast::StmtAssign { targets, value, .. }) => {
|
||||
if let ExprKind::Call(ast::ExprCall { func, .. }) = &value.node {
|
||||
Stmt::Assign(ast::StmtAssign { targets, value, .. }) => {
|
||||
if let Expr::Call(ast::ExprCall { func, .. }) = value.as_ref() {
|
||||
if helpers::is_model_field(&checker.ctx, func) {
|
||||
return Some(ContentType::FieldDeclaration);
|
||||
}
|
||||
|
@ -110,7 +110,7 @@ fn get_element_type(checker: &Checker, element: &StmtKind) -> Option<ContentType
|
|||
let Some(expr) = targets.first() else {
|
||||
return None;
|
||||
};
|
||||
let ExprKind::Name(ast::ExprName { id, .. }) = &expr.node else {
|
||||
let Expr::Name(ast::ExprName { id, .. }) = expr else {
|
||||
return None;
|
||||
};
|
||||
if id == "objects" {
|
||||
|
@ -119,14 +119,14 @@ fn get_element_type(checker: &Checker, element: &StmtKind) -> Option<ContentType
|
|||
None
|
||||
}
|
||||
}
|
||||
StmtKind::ClassDef(ast::StmtClassDef { name, .. }) => {
|
||||
Stmt::ClassDef(ast::StmtClassDef { name, .. }) => {
|
||||
if name == "Meta" {
|
||||
Some(ContentType::MetaClass)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
StmtKind::FunctionDef(ast::StmtFunctionDef { name, .. }) => match name.as_str() {
|
||||
Stmt::FunctionDef(ast::StmtFunctionDef { name, .. }) => match name.as_str() {
|
||||
"__str__" => Some(ContentType::StrMethod),
|
||||
"save" => Some(ContentType::SaveMethod),
|
||||
"get_absolute_url" => Some(ContentType::GetAbsoluteUrlMethod),
|
||||
|
@ -150,7 +150,7 @@ pub(crate) fn unordered_body_content_in_model(
|
|||
}
|
||||
let mut elements_type_found = Vec::new();
|
||||
for element in body.iter() {
|
||||
let Some(current_element_type) = get_element_type(checker, &element.node) else {
|
||||
let Some(current_element_type) = get_element_type(checker, element) else {
|
||||
continue;
|
||||
};
|
||||
let Some(&element_type) = elements_type_found
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
use rustpython_parser::ast::{self, Constant, Expr, ExprContext, ExprKind, Stmt, StmtKind};
|
||||
use ruff_text_size::TextRange;
|
||||
use rustpython_parser::ast::{self, Constant, Expr, ExprContext, Ranged, Stmt};
|
||||
|
||||
use ruff_diagnostics::{AutofixKind, Diagnostic, Edit, Fix, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
use ruff_python_ast::helpers::{create_expr, create_stmt, unparse_stmt};
|
||||
use ruff_python_ast::helpers::unparse_stmt;
|
||||
use ruff_python_ast::source_code::Stylist;
|
||||
use ruff_python_ast::whitespace;
|
||||
|
||||
|
@ -183,17 +184,18 @@ impl Violation for DotFormatInException {
|
|||
/// `raise` statement. The variable name is `msg`.
|
||||
/// 2. Replace the exception argument with the variable name.
|
||||
fn generate_fix(stylist: &Stylist, stmt: &Stmt, exc_arg: &Expr, indentation: &str) -> Fix {
|
||||
let assignment = unparse_stmt(
|
||||
&create_stmt(StmtKind::Assign(ast::StmtAssign {
|
||||
targets: vec![create_expr(ExprKind::Name(ast::ExprName {
|
||||
let node = Expr::Name(ast::ExprName {
|
||||
id: "msg".into(),
|
||||
ctx: ExprContext::Store,
|
||||
}))],
|
||||
range: TextRange::default(),
|
||||
});
|
||||
let node1 = Stmt::Assign(ast::StmtAssign {
|
||||
targets: vec![node],
|
||||
value: Box::new(exc_arg.clone()),
|
||||
type_comment: None,
|
||||
})),
|
||||
stylist,
|
||||
);
|
||||
range: TextRange::default(),
|
||||
});
|
||||
let assignment = unparse_stmt(&node1, stylist);
|
||||
#[allow(deprecated)]
|
||||
Fix::unspecified_edits(
|
||||
Edit::insertion(
|
||||
|
@ -214,11 +216,11 @@ fn generate_fix(stylist: &Stylist, stmt: &Stmt, exc_arg: &Expr, indentation: &st
|
|||
|
||||
/// EM101, EM102, EM103
|
||||
pub(crate) fn string_in_exception(checker: &mut Checker, stmt: &Stmt, exc: &Expr) {
|
||||
if let ExprKind::Call(ast::ExprCall { args, .. }) = &exc.node {
|
||||
if let Expr::Call(ast::ExprCall { args, .. }) = exc {
|
||||
if let Some(first) = args.first() {
|
||||
match &first.node {
|
||||
match first {
|
||||
// Check for string literals
|
||||
ExprKind::Constant(ast::ExprConstant {
|
||||
Expr::Constant(ast::ExprConstant {
|
||||
value: Constant::Str(string),
|
||||
..
|
||||
}) => {
|
||||
|
@ -249,7 +251,7 @@ pub(crate) fn string_in_exception(checker: &mut Checker, stmt: &Stmt, exc: &Expr
|
|||
}
|
||||
}
|
||||
// Check for f-strings
|
||||
ExprKind::JoinedStr(_) => {
|
||||
Expr::JoinedStr(_) => {
|
||||
if checker.settings.rules.enabled(Rule::FStringInException) {
|
||||
let indentation = whitespace::indentation(checker.locator, stmt).and_then(
|
||||
|indentation| {
|
||||
|
@ -275,12 +277,12 @@ pub(crate) fn string_in_exception(checker: &mut Checker, stmt: &Stmt, exc: &Expr
|
|||
}
|
||||
}
|
||||
// Check for .format() calls
|
||||
ExprKind::Call(ast::ExprCall { func, .. }) => {
|
||||
Expr::Call(ast::ExprCall { func, .. }) => {
|
||||
if checker.settings.rules.enabled(Rule::DotFormatInException) {
|
||||
if let ExprKind::Attribute(ast::ExprAttribute { value, attr, .. }) =
|
||||
&func.node
|
||||
if let Expr::Attribute(ast::ExprAttribute { value, attr, .. }) =
|
||||
func.as_ref()
|
||||
{
|
||||
if attr == "format" && matches!(value.node, ExprKind::Constant(_)) {
|
||||
if attr == "format" && value.is_constant_expr() {
|
||||
let indentation = whitespace::indentation(checker.locator, stmt)
|
||||
.and_then(|indentation| {
|
||||
if checker.ctx.find_binding("msg").is_none() {
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue