Refactor range from Attributed to Nodes (#4422)

This commit is contained in:
Micha Reiser 2023-05-16 08:36:32 +02:00 committed by GitHub
parent 140e0acf54
commit fa26860296
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
330 changed files with 4816 additions and 3946 deletions

24
Cargo.lock generated
View file

@ -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",
]

View file

@ -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"] }

View file

@ -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

View file

@ -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"),
}
}

View file

@ -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);
}

View file

@ -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()),

View file

@ -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 {

View file

@ -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()
}

View file

@ -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)?;

View file

@ -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 {

View file

@ -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;

View file

@ -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,

View file

@ -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(),
));

View file

@ -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()));
}
}
}

View file

@ -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

View file

@ -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};

View file

@ -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))
{

View file

@ -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" {

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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,
};

View file

@ -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,
}
}

View file

@ -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};

View file

@ -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),
..
})

View file

@ -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 },

View file

@ -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};

View file

@ -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 {

View file

@ -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)),

View file

@ -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 {

View file

@ -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

View file

@ -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};

View file

@ -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;
};

View file

@ -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

View file

@ -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

View file

@ -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(

View file

@ -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;
}
}

View file

@ -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",

View file

@ -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;
};

View file

@ -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;
};

View file

@ -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 {

View file

@ -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" {

View file

@ -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,
},
) {

View file

@ -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

View file

@ -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);

View file

@ -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() {

View file

@ -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

View file

@ -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(

View file

@ -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();

View file

@ -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(),
));
}
}

View file

@ -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) {

View file

@ -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(_))
});
}

View file

@ -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),

View file

@ -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))

View file

@ -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};

View file

@ -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

View file

@ -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 {

View file

@ -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`

View file

@ -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());

View file

@ -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() {

View file

@ -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;
};

View file

@ -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) {

View file

@ -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

View file

@ -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;
};

View file

@ -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);

View file

@ -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()));

View file

@ -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};

View file

@ -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,

View file

@ -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

View file

@ -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 {

View file

@ -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 {

View file

@ -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
}

View file

@ -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 {

View file

@ -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)`)
}

View file

@ -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 {

View file

@ -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(_)))
}

View file

@ -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 {

View file

@ -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)]

View file

@ -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)]

View file

@ -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)]

View file

@ -1,4 +1,4 @@
use rustpython_parser::ast::Expr;
use rustpython_parser::ast::{Expr, Ranged};
use crate::checkers::ast::Checker;
use crate::registry::AsRule;

View file

@ -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 {

View file

@ -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};

View file

@ -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(

View file

@ -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(

View file

@ -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(

View file

@ -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(

View file

@ -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(

View file

@ -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()) {

View file

@ -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) {

View file

@ -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" {

View file

@ -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;

View file

@ -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()));

View file

@ -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" {

View file

@ -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

View file

@ -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;

View file

@ -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"]
}),

View file

@ -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() {

View file

@ -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

View file

@ -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