mirror of
https://github.com/astral-sh/ruff.git
synced 2025-08-04 10:49:50 +00:00
Split Constant
to individual literal nodes (#8064)
## Summary This PR splits the `Constant` enum as individual literal nodes. It introduces the following new nodes for each variant: * `ExprStringLiteral` * `ExprBytesLiteral` * `ExprNumberLiteral` * `ExprBooleanLiteral` * `ExprNoneLiteral` * `ExprEllipsisLiteral` The main motivation behind this refactor is to introduce the new AST node for implicit string concatenation in the coming PR. The elements of that node will be either a string literal, bytes literal or a f-string which can be implemented using an enum. This means that a string or bytes literal cannot be represented by `Constant::Str` / `Constant::Bytes` which creates an inconsistency. This PR avoids that inconsistency by splitting the constant nodes into it's own literal nodes, literal being the more appropriate naming convention from a static analysis tool perspective. This also makes working with literals in the linter and formatter much more ergonomic like, for example, if one would want to check if this is a string literal, it can be done easily using `Expr::is_string_literal_expr` or matching against `Expr::StringLiteral` as oppose to matching against the `ExprConstant` and enum `Constant`. A few AST helper methods can be simplified as well which will be done in a follow-up PR. This introduces a new `Expr::is_literal_expr` method which is the same as `Expr::is_constant_expr`. There are also intermediary changes related to implicit string concatenation which are quiet less. This is done so as to avoid having a huge PR which this already is. ## Test Plan 1. Verify and update all of the existing snapshots (parser, visitor) 2. Verify that the ecosystem check output remains **unchanged** for both the linter and formatter ### Formatter ecosystem check #### `main` | project | similarity index | total files | changed files | |----------------|------------------:|------------------:|------------------:| | cpython | 0.75803 | 1799 | 1647 | | django | 0.99983 | 2772 | 34 | | home-assistant | 0.99953 | 10596 | 186 | | poetry | 0.99891 | 317 | 17 | | transformers | 0.99966 | 2657 | 330 | | twine | 1.00000 | 33 | 0 | | typeshed | 0.99978 | 3669 | 20 | | warehouse | 0.99977 | 654 | 13 | | zulip | 0.99970 | 1459 | 22 | #### `dhruv/constant-to-literal` | project | similarity index | total files | changed files | |----------------|------------------:|------------------:|------------------:| | cpython | 0.75803 | 1799 | 1647 | | django | 0.99983 | 2772 | 34 | | home-assistant | 0.99953 | 10596 | 186 | | poetry | 0.99891 | 317 | 17 | | transformers | 0.99966 | 2657 | 330 | | twine | 1.00000 | 33 | 0 | | typeshed | 0.99978 | 3669 | 20 | | warehouse | 0.99977 | 654 | 13 | | zulip | 0.99970 | 1459 | 22 |
This commit is contained in:
parent
78bbf6d403
commit
230c9ce236
268 changed files with 6663 additions and 6741 deletions
|
@ -170,7 +170,7 @@ pub(crate) fn definitions(checker: &mut Checker) {
|
|||
expr.start(),
|
||||
));
|
||||
|
||||
if pydocstyle::helpers::should_ignore_docstring(expr) {
|
||||
if expr.implicit_concatenated {
|
||||
#[allow(deprecated)]
|
||||
let location = checker.locator.compute_source_location(expr.start());
|
||||
warn_user!(
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use ruff_python_ast::{self as ast, Arguments, Constant, Expr, ExprContext, Operator};
|
||||
use ruff_python_ast::{self as ast, Arguments, Expr, ExprContext, Operator};
|
||||
use ruff_python_literal::cformat::{CFormatError, CFormatErrorType};
|
||||
|
||||
use ruff_diagnostics::Diagnostic;
|
||||
|
@ -363,20 +363,18 @@ pub(crate) fn expression(expr: &Expr, checker: &mut Checker) {
|
|||
]) {
|
||||
if let Expr::Attribute(ast::ExprAttribute { value, attr, .. }) = func.as_ref() {
|
||||
let attr = attr.as_str();
|
||||
if let Expr::Constant(ast::ExprConstant {
|
||||
value: Constant::Str(val),
|
||||
..
|
||||
}) = value.as_ref()
|
||||
if let Expr::StringLiteral(ast::ExprStringLiteral { value: string, .. }) =
|
||||
value.as_ref()
|
||||
{
|
||||
if attr == "join" {
|
||||
// "...".join(...) call
|
||||
if checker.enabled(Rule::StaticJoinToFString) {
|
||||
flynt::rules::static_join_to_fstring(checker, expr, val);
|
||||
flynt::rules::static_join_to_fstring(checker, expr, string);
|
||||
}
|
||||
} else if attr == "format" {
|
||||
// "...".format(...) call
|
||||
let location = expr.range();
|
||||
match pyflakes::format::FormatSummary::try_from(val.as_ref()) {
|
||||
match pyflakes::format::FormatSummary::try_from(string.as_ref()) {
|
||||
Err(e) => {
|
||||
if checker.enabled(Rule::StringDotFormatInvalidFormat) {
|
||||
checker.diagnostics.push(Diagnostic::new(
|
||||
|
@ -421,7 +419,7 @@ pub(crate) fn expression(expr: &Expr, checker: &mut Checker) {
|
|||
|
||||
if checker.enabled(Rule::BadStringFormatCharacter) {
|
||||
pylint::rules::bad_string_format_character::call(
|
||||
checker, val, location,
|
||||
checker, string, location,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -993,11 +991,7 @@ pub(crate) fn expression(expr: &Expr, checker: &mut Checker) {
|
|||
right,
|
||||
range: _,
|
||||
}) => {
|
||||
if let Expr::Constant(ast::ExprConstant {
|
||||
value: Constant::Str(ast::StringConstant { value, .. }),
|
||||
..
|
||||
}) = left.as_ref()
|
||||
{
|
||||
if let Expr::StringLiteral(ast::ExprStringLiteral { value, .. }) = left.as_ref() {
|
||||
if checker.any_enabled(&[
|
||||
Rule::PercentFormatInvalidFormat,
|
||||
Rule::PercentFormatExpectedMapping,
|
||||
|
@ -1234,38 +1228,29 @@ pub(crate) fn expression(expr: &Expr, checker: &mut Checker) {
|
|||
refurb::rules::single_item_membership_test(checker, expr, left, ops, comparators);
|
||||
}
|
||||
}
|
||||
Expr::Constant(ast::ExprConstant {
|
||||
value: Constant::Int(_) | Constant::Float(_) | Constant::Complex { .. },
|
||||
range: _,
|
||||
}) => {
|
||||
Expr::NumberLiteral(_) => {
|
||||
if checker.source_type.is_stub() && checker.enabled(Rule::NumericLiteralTooLong) {
|
||||
flake8_pyi::rules::numeric_literal_too_long(checker, expr);
|
||||
}
|
||||
}
|
||||
Expr::Constant(ast::ExprConstant {
|
||||
value: Constant::Bytes(_),
|
||||
range: _,
|
||||
}) => {
|
||||
Expr::BytesLiteral(_) => {
|
||||
if checker.source_type.is_stub() && checker.enabled(Rule::StringOrBytesTooLong) {
|
||||
flake8_pyi::rules::string_or_bytes_too_long(checker, expr);
|
||||
}
|
||||
}
|
||||
Expr::Constant(ast::ExprConstant {
|
||||
value: Constant::Str(value),
|
||||
range: _,
|
||||
}) => {
|
||||
Expr::StringLiteral(string) => {
|
||||
if checker.enabled(Rule::HardcodedBindAllInterfaces) {
|
||||
if let Some(diagnostic) =
|
||||
flake8_bandit::rules::hardcoded_bind_all_interfaces(value, expr.range())
|
||||
flake8_bandit::rules::hardcoded_bind_all_interfaces(string)
|
||||
{
|
||||
checker.diagnostics.push(diagnostic);
|
||||
}
|
||||
}
|
||||
if checker.enabled(Rule::HardcodedTempFile) {
|
||||
flake8_bandit::rules::hardcoded_tmp_directory(checker, expr, value);
|
||||
flake8_bandit::rules::hardcoded_tmp_directory(checker, string);
|
||||
}
|
||||
if checker.enabled(Rule::UnicodeKindPrefix) {
|
||||
pyupgrade::rules::unicode_kind_prefix(checker, expr, value.unicode);
|
||||
pyupgrade::rules::unicode_kind_prefix(checker, string);
|
||||
}
|
||||
if checker.source_type.is_stub() {
|
||||
if checker.enabled(Rule::StringOrBytesTooLong) {
|
||||
|
|
|
@ -31,9 +31,8 @@ use std::path::Path;
|
|||
use itertools::Itertools;
|
||||
use log::debug;
|
||||
use ruff_python_ast::{
|
||||
self as ast, Arguments, Comprehension, Constant, ElifElseClause, ExceptHandler, Expr,
|
||||
ExprContext, Keyword, MatchCase, Parameter, ParameterWithDefault, Parameters, Pattern, Stmt,
|
||||
Suite, UnaryOp,
|
||||
self as ast, Arguments, Comprehension, ElifElseClause, ExceptHandler, Expr, ExprContext,
|
||||
Keyword, MatchCase, Parameter, ParameterWithDefault, Parameters, Pattern, Stmt, Suite, UnaryOp,
|
||||
};
|
||||
use ruff_text_size::{Ranged, TextRange, TextSize};
|
||||
|
||||
|
@ -787,11 +786,7 @@ where
|
|||
&& self.semantic.in_type_definition()
|
||||
&& self.semantic.future_annotations()
|
||||
{
|
||||
if let Expr::Constant(ast::ExprConstant {
|
||||
value: Constant::Str(value),
|
||||
..
|
||||
}) = expr
|
||||
{
|
||||
if let Expr::StringLiteral(ast::ExprStringLiteral { value, .. }) = expr {
|
||||
self.deferred.string_type_definitions.push((
|
||||
expr.range(),
|
||||
value,
|
||||
|
@ -1186,10 +1181,7 @@ where
|
|||
}
|
||||
}
|
||||
}
|
||||
Expr::Constant(ast::ExprConstant {
|
||||
value: Constant::Str(value),
|
||||
range: _,
|
||||
}) => {
|
||||
Expr::StringLiteral(ast::ExprStringLiteral { value, .. }) => {
|
||||
if self.semantic.in_type_definition()
|
||||
&& !self.semantic.in_literal()
|
||||
&& !self.semantic.in_f_string()
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
use std::iter::FusedIterator;
|
||||
|
||||
use ruff_python_ast::{self as ast, Constant, Expr, Stmt, Suite};
|
||||
use ruff_python_ast::{self as ast, Stmt, Suite};
|
||||
use ruff_python_parser::lexer::LexResult;
|
||||
use ruff_python_parser::Tok;
|
||||
use ruff_text_size::{Ranged, TextSize};
|
||||
|
@ -69,15 +69,15 @@ struct StringLinesVisitor<'a> {
|
|||
|
||||
impl StatementVisitor<'_> for StringLinesVisitor<'_> {
|
||||
fn visit_stmt(&mut self, stmt: &Stmt) {
|
||||
if let Stmt::Expr(ast::StmtExpr { value, range: _ }) = stmt {
|
||||
if let Expr::Constant(ast::ExprConstant {
|
||||
value: Constant::Str(..),
|
||||
..
|
||||
}) = value.as_ref()
|
||||
{
|
||||
if let Stmt::Expr(ast::StmtExpr {
|
||||
value: expr,
|
||||
range: _,
|
||||
}) = stmt
|
||||
{
|
||||
if expr.is_string_literal_expr() {
|
||||
for line in UniversalNewlineIterator::with_offset(
|
||||
self.locator.slice(value.as_ref()),
|
||||
value.start(),
|
||||
self.locator.slice(expr.as_ref()),
|
||||
expr.start(),
|
||||
) {
|
||||
self.string_lines.push(line.start());
|
||||
}
|
||||
|
|
|
@ -1,30 +1,23 @@
|
|||
//! Extract docstrings from an AST.
|
||||
|
||||
use ruff_python_ast::{self as ast, Constant, Expr, Stmt};
|
||||
use ruff_python_ast::{self as ast, Stmt};
|
||||
use ruff_python_semantic::{Definition, DefinitionId, Definitions, Member, MemberKind};
|
||||
|
||||
/// Extract a docstring from a function or class body.
|
||||
pub(crate) fn docstring_from(suite: &[Stmt]) -> Option<&Expr> {
|
||||
pub(crate) fn docstring_from(suite: &[Stmt]) -> Option<&ast::ExprStringLiteral> {
|
||||
let stmt = suite.first()?;
|
||||
// Require the docstring to be a standalone expression.
|
||||
let Stmt::Expr(ast::StmtExpr { value, range: _ }) = stmt else {
|
||||
return None;
|
||||
};
|
||||
// Only match strings.
|
||||
if !matches!(
|
||||
value.as_ref(),
|
||||
Expr::Constant(ast::ExprConstant {
|
||||
value: Constant::Str(_),
|
||||
..
|
||||
})
|
||||
) {
|
||||
return None;
|
||||
}
|
||||
Some(value)
|
||||
value.as_string_literal_expr()
|
||||
}
|
||||
|
||||
/// Extract a docstring from a `Definition`.
|
||||
pub(crate) fn extract_docstring<'a>(definition: &'a Definition<'a>) -> Option<&'a Expr> {
|
||||
pub(crate) fn extract_docstring<'a>(
|
||||
definition: &'a Definition<'a>,
|
||||
) -> Option<&'a ast::ExprStringLiteral> {
|
||||
match definition {
|
||||
Definition::Module(module) => docstring_from(module.python_ast),
|
||||
Definition::Member(member) => docstring_from(member.body()),
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use std::fmt::{Debug, Formatter};
|
||||
use std::ops::Deref;
|
||||
|
||||
use ruff_python_ast::Expr;
|
||||
use ruff_python_ast::ExprStringLiteral;
|
||||
use ruff_python_semantic::Definition;
|
||||
use ruff_text_size::{Ranged, TextRange};
|
||||
|
||||
|
@ -14,7 +14,8 @@ pub(crate) mod styles;
|
|||
#[derive(Debug)]
|
||||
pub(crate) struct Docstring<'a> {
|
||||
pub(crate) definition: &'a Definition<'a>,
|
||||
pub(crate) expr: &'a Expr,
|
||||
/// The literal AST node representing the docstring.
|
||||
pub(crate) expr: &'a ExprStringLiteral,
|
||||
/// The content of the docstring, including the leading and trailing quotes.
|
||||
pub(crate) contents: &'a str,
|
||||
/// The range of the docstring body (without the quotes). The range is relative to [`Self::contents`].
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
use ruff_python_ast as ast;
|
||||
use ruff_python_ast::Constant;
|
||||
use ruff_python_ast::Expr;
|
||||
use ruff_text_size::Ranged;
|
||||
|
||||
|
@ -79,13 +78,7 @@ pub(crate) fn variable_name_task_id(
|
|||
let keyword = arguments.find_keyword("task_id")?;
|
||||
|
||||
// If the keyword argument is not a string, we can't do anything.
|
||||
let task_id = match &keyword.value {
|
||||
Expr::Constant(constant) => match &constant.value {
|
||||
Constant::Str(ast::StringConstant { value, .. }) => value,
|
||||
_ => return None,
|
||||
},
|
||||
_ => return None,
|
||||
};
|
||||
let ast::ExprStringLiteral { value: task_id, .. } = keyword.value.as_string_literal_expr()?;
|
||||
|
||||
// If the target name is the same as the task_id, no violation.
|
||||
if id == task_id {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
use ruff_python_ast::{self as ast, CmpOp, Constant, Expr};
|
||||
use ruff_python_ast::{self as ast, CmpOp, Expr};
|
||||
use ruff_text_size::Ranged;
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
|
@ -230,16 +230,16 @@ pub(crate) fn compare(checker: &mut Checker, left: &Expr, ops: &[CmpOp], compara
|
|||
Expr::Subscript(ast::ExprSubscript { value, slice, .. })
|
||||
if is_sys(value, "version_info", checker.semantic()) =>
|
||||
{
|
||||
if let Expr::Constant(ast::ExprConstant {
|
||||
value: Constant::Int(i),
|
||||
if let Expr::NumberLiteral(ast::ExprNumberLiteral {
|
||||
value: ast::Number::Int(i),
|
||||
..
|
||||
}) = slice.as_ref()
|
||||
{
|
||||
if *i == 0 {
|
||||
if let (
|
||||
[CmpOp::Eq | CmpOp::NotEq],
|
||||
[Expr::Constant(ast::ExprConstant {
|
||||
value: Constant::Int(n),
|
||||
[Expr::NumberLiteral(ast::ExprNumberLiteral {
|
||||
value: ast::Number::Int(n),
|
||||
..
|
||||
})],
|
||||
) = (ops, comparators)
|
||||
|
@ -253,8 +253,8 @@ pub(crate) fn compare(checker: &mut Checker, left: &Expr, ops: &[CmpOp], compara
|
|||
} else if *i == 1 {
|
||||
if let (
|
||||
[CmpOp::Lt | CmpOp::LtE | CmpOp::Gt | CmpOp::GtE],
|
||||
[Expr::Constant(ast::ExprConstant {
|
||||
value: Constant::Int(_),
|
||||
[Expr::NumberLiteral(ast::ExprNumberLiteral {
|
||||
value: ast::Number::Int(_),
|
||||
..
|
||||
})],
|
||||
) = (ops, comparators)
|
||||
|
@ -274,8 +274,8 @@ pub(crate) fn compare(checker: &mut Checker, left: &Expr, ops: &[CmpOp], compara
|
|||
{
|
||||
if let (
|
||||
[CmpOp::Lt | CmpOp::LtE | CmpOp::Gt | CmpOp::GtE],
|
||||
[Expr::Constant(ast::ExprConstant {
|
||||
value: Constant::Int(_),
|
||||
[Expr::NumberLiteral(ast::ExprNumberLiteral {
|
||||
value: ast::Number::Int(_),
|
||||
..
|
||||
})],
|
||||
) = (ops, comparators)
|
||||
|
@ -294,13 +294,10 @@ pub(crate) fn compare(checker: &mut Checker, left: &Expr, ops: &[CmpOp], compara
|
|||
if is_sys(left, "version", checker.semantic()) {
|
||||
if let (
|
||||
[CmpOp::Lt | CmpOp::LtE | CmpOp::Gt | CmpOp::GtE],
|
||||
[Expr::Constant(ast::ExprConstant {
|
||||
value: Constant::Str(s),
|
||||
..
|
||||
})],
|
||||
[Expr::StringLiteral(ast::ExprStringLiteral { value, .. })],
|
||||
) = (ops, comparators)
|
||||
{
|
||||
if s.len() == 1 {
|
||||
if value.len() == 1 {
|
||||
if checker.enabled(Rule::SysVersionCmpStr10) {
|
||||
checker
|
||||
.diagnostics
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
use ruff_python_ast::{self as ast, Constant, Expr};
|
||||
use ruff_python_ast::{self as ast, Expr};
|
||||
use ruff_text_size::Ranged;
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
|
@ -177,8 +177,8 @@ pub(crate) fn subscript(checker: &mut Checker, value: &Expr, slice: &Expr) {
|
|||
step: None,
|
||||
range: _,
|
||||
}) => {
|
||||
if let Expr::Constant(ast::ExprConstant {
|
||||
value: Constant::Int(i),
|
||||
if let Expr::NumberLiteral(ast::ExprNumberLiteral {
|
||||
value: ast::Number::Int(i),
|
||||
..
|
||||
}) = upper.as_ref()
|
||||
{
|
||||
|
@ -194,8 +194,8 @@ pub(crate) fn subscript(checker: &mut Checker, value: &Expr, slice: &Expr) {
|
|||
}
|
||||
}
|
||||
|
||||
Expr::Constant(ast::ExprConstant {
|
||||
value: Constant::Int(i),
|
||||
Expr::NumberLiteral(ast::ExprNumberLiteral {
|
||||
value: ast::Number::Int(i),
|
||||
..
|
||||
}) => {
|
||||
if *i == 2 && checker.enabled(Rule::SysVersion2) {
|
||||
|
|
|
@ -3,7 +3,7 @@ use ruff_macros::{derive_message_formats, violation};
|
|||
use ruff_python_ast::helpers::ReturnStatementVisitor;
|
||||
use ruff_python_ast::identifier::Identifier;
|
||||
use ruff_python_ast::statement_visitor::StatementVisitor;
|
||||
use ruff_python_ast::{self as ast, Constant, Expr, ParameterWithDefault, Stmt};
|
||||
use ruff_python_ast::{self as ast, Expr, ParameterWithDefault, Stmt};
|
||||
use ruff_python_parser::typing::parse_type_annotation;
|
||||
use ruff_python_semantic::analyze::visibility;
|
||||
use ruff_python_semantic::Definition;
|
||||
|
@ -431,10 +431,7 @@ fn is_none_returning(body: &[Stmt]) -> bool {
|
|||
visitor.visit_body(body);
|
||||
for stmt in visitor.returns {
|
||||
if let Some(value) = stmt.value.as_deref() {
|
||||
if !matches!(
|
||||
value,
|
||||
Expr::Constant(constant) if constant.value.is_none()
|
||||
) {
|
||||
if !value.is_none_literal_expr() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -451,9 +448,10 @@ fn check_dynamically_typed<F>(
|
|||
) where
|
||||
F: FnOnce() -> String,
|
||||
{
|
||||
if let Expr::Constant(ast::ExprConstant {
|
||||
if let Expr::StringLiteral(ast::ExprStringLiteral {
|
||||
range,
|
||||
value: Constant::Str(string),
|
||||
value: string,
|
||||
..
|
||||
}) = annotation
|
||||
{
|
||||
// Quoted annotations
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use once_cell::sync::Lazy;
|
||||
use regex::Regex;
|
||||
use ruff_python_ast::{self as ast, Constant, Expr};
|
||||
use ruff_python_ast::{self as ast, Expr};
|
||||
|
||||
use ruff_python_semantic::SemanticModel;
|
||||
|
||||
|
@ -10,10 +10,7 @@ static PASSWORD_CANDIDATE_REGEX: Lazy<Regex> = Lazy::new(|| {
|
|||
|
||||
pub(super) fn string_literal(expr: &Expr) -> Option<&str> {
|
||||
match expr {
|
||||
Expr::Constant(ast::ExprConstant {
|
||||
value: Constant::Str(string),
|
||||
..
|
||||
}) => Some(string),
|
||||
Expr::StringLiteral(ast::ExprStringLiteral { value, .. }) => Some(value),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@ use anyhow::Result;
|
|||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
use ruff_python_ast::call_path::CallPath;
|
||||
use ruff_python_ast::{self as ast, Constant, Expr, Operator};
|
||||
use ruff_python_ast::{self as ast, Expr, Operator};
|
||||
use ruff_python_semantic::SemanticModel;
|
||||
use ruff_text_size::Ranged;
|
||||
|
||||
|
@ -144,8 +144,8 @@ fn py_stat(call_path: &CallPath) -> Option<u16> {
|
|||
/// an integer value, but that value is out of range.
|
||||
fn parse_mask(expr: &Expr, semantic: &SemanticModel) -> Result<Option<u16>> {
|
||||
match expr {
|
||||
Expr::Constant(ast::ExprConstant {
|
||||
value: Constant::Int(int),
|
||||
Expr::NumberLiteral(ast::ExprNumberLiteral {
|
||||
value: ast::Number::Int(int),
|
||||
..
|
||||
}) => match int.as_u16() {
|
||||
Some(value) => Ok(Some(value)),
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
use ruff_text_size::TextRange;
|
||||
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
use ruff_python_ast::ExprStringLiteral;
|
||||
|
||||
/// ## What it does
|
||||
/// Checks for hardcoded bindings to all network interfaces (`0.0.0.0`).
|
||||
|
@ -35,9 +34,9 @@ impl Violation for HardcodedBindAllInterfaces {
|
|||
}
|
||||
|
||||
/// S104
|
||||
pub(crate) fn hardcoded_bind_all_interfaces(value: &str, range: TextRange) -> Option<Diagnostic> {
|
||||
if value == "0.0.0.0" {
|
||||
Some(Diagnostic::new(HardcodedBindAllInterfaces, range))
|
||||
pub(crate) fn hardcoded_bind_all_interfaces(string: &ExprStringLiteral) -> Option<Diagnostic> {
|
||||
if string.value == "0.0.0.0" {
|
||||
Some(Diagnostic::new(HardcodedBindAllInterfaces, string.range))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
use ruff_python_ast::{self as ast, Constant, Expr};
|
||||
use ruff_python_ast::{self as ast, Expr};
|
||||
use ruff_text_size::Ranged;
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
|
@ -55,10 +55,7 @@ fn password_target(target: &Expr) -> Option<&str> {
|
|||
Expr::Name(ast::ExprName { id, .. }) => id.as_str(),
|
||||
// d["password"] = "s3cr3t"
|
||||
Expr::Subscript(ast::ExprSubscript { slice, .. }) => match slice.as_ref() {
|
||||
Expr::Constant(ast::ExprConstant {
|
||||
value: Constant::Str(string),
|
||||
..
|
||||
}) => string,
|
||||
Expr::StringLiteral(ast::ExprStringLiteral { value, .. }) => value,
|
||||
_ => return None,
|
||||
},
|
||||
// obj.password = "s3cr3t"
|
||||
|
|
|
@ -2,7 +2,6 @@ use ruff_python_ast::{self as ast, Expr};
|
|||
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
use ruff_text_size::Ranged;
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
|
||||
|
@ -52,13 +51,13 @@ impl Violation for HardcodedTempFile {
|
|||
}
|
||||
|
||||
/// S108
|
||||
pub(crate) fn hardcoded_tmp_directory(checker: &mut Checker, expr: &Expr, value: &str) {
|
||||
pub(crate) fn hardcoded_tmp_directory(checker: &mut Checker, string: &ast::ExprStringLiteral) {
|
||||
if !checker
|
||||
.settings
|
||||
.flake8_bandit
|
||||
.hardcoded_tmp_directory
|
||||
.iter()
|
||||
.any(|prefix| value.starts_with(prefix))
|
||||
.any(|prefix| string.value.starts_with(prefix))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
@ -77,8 +76,8 @@ pub(crate) fn hardcoded_tmp_directory(checker: &mut Checker, expr: &Expr, value:
|
|||
|
||||
checker.diagnostics.push(Diagnostic::new(
|
||||
HardcodedTempFile {
|
||||
string: value.to_string(),
|
||||
string: string.value.clone(),
|
||||
},
|
||||
expr.range(),
|
||||
string.range,
|
||||
));
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
use ruff_python_ast::{self as ast, Constant, Expr};
|
||||
use ruff_python_ast::{self as ast, Expr};
|
||||
use ruff_text_size::Ranged;
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
|
@ -66,10 +66,7 @@ pub(crate) fn jinja2_autoescape_false(checker: &mut Checker, call: &ast::ExprCal
|
|||
{
|
||||
if let Some(keyword) = call.arguments.find_keyword("autoescape") {
|
||||
match &keyword.value {
|
||||
Expr::Constant(ast::ExprConstant {
|
||||
value: Constant::Bool(true),
|
||||
..
|
||||
}) => (),
|
||||
Expr::BooleanLiteral(ast::ExprBooleanLiteral { value: true, .. }) => (),
|
||||
Expr::Call(ast::ExprCall { func, .. }) => {
|
||||
if let Expr::Name(ast::ExprName { id, .. }) = func.as_ref() {
|
||||
if id != "select_autoescape" {
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
use ruff_python_ast::helpers::Truthiness;
|
||||
use ruff_python_ast::{self as ast, Arguments, Constant, Expr, Keyword};
|
||||
use ruff_python_ast::{self as ast, Arguments, Expr, Keyword};
|
||||
use ruff_python_semantic::SemanticModel;
|
||||
use ruff_text_size::Ranged;
|
||||
|
||||
|
@ -456,13 +456,7 @@ fn find_shell_keyword<'a>(
|
|||
/// Return `true` if the value provided to the `shell` call seems safe. This is based on Bandit's
|
||||
/// definition: string literals are considered okay, but dynamically-computed values are not.
|
||||
fn shell_call_seems_safe(arg: &Expr) -> bool {
|
||||
matches!(
|
||||
arg,
|
||||
Expr::Constant(ast::ExprConstant {
|
||||
value: Constant::Str(_),
|
||||
..
|
||||
})
|
||||
)
|
||||
arg.is_string_literal_expr()
|
||||
}
|
||||
|
||||
/// Return `true` if the string appears to be a full file path.
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
use ruff_python_ast::{self as ast, Constant, Expr, Int};
|
||||
use ruff_python_ast::{self as ast, Expr, Int};
|
||||
use ruff_text_size::Ranged;
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
|
@ -52,8 +52,8 @@ pub(crate) fn snmp_insecure_version(checker: &mut Checker, call: &ast::ExprCall)
|
|||
if let Some(keyword) = call.arguments.find_keyword("mpModel") {
|
||||
if matches!(
|
||||
keyword.value,
|
||||
Expr::Constant(ast::ExprConstant {
|
||||
value: Constant::Int(Int::ZERO | Int::ONE),
|
||||
Expr::NumberLiteral(ast::ExprNumberLiteral {
|
||||
value: ast::Number::Int(Int::ZERO | Int::ONE),
|
||||
..
|
||||
})
|
||||
) {
|
||||
|
|
|
@ -854,7 +854,7 @@ pub(crate) fn suspicious_function_call(checker: &mut Checker, call: &ExprCall) {
|
|||
["six", "moves", "urllib", "request", "urlopen" | "urlretrieve" | "Request"] => {
|
||||
// If the `url` argument is a string literal, allow `http` and `https` schemes.
|
||||
if call.arguments.args.iter().all(|arg| !arg.is_starred_expr()) && call.arguments.keywords.iter().all(|keyword| keyword.arg.is_some()) {
|
||||
if let Some(Expr::Constant(ast::ExprConstant { value: ast::Constant::Str(url), .. })) = &call.arguments.find_argument("url", 0) {
|
||||
if let Some(Expr::StringLiteral(ast::ExprStringLiteral { value: url, .. })) = &call.arguments.find_argument("url", 0) {
|
||||
let url = url.trim_start();
|
||||
if url.starts_with("http://") || url.starts_with("https://") {
|
||||
return None;
|
||||
|
|
|
@ -2,7 +2,7 @@ use std::fmt::{Display, Formatter};
|
|||
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
use ruff_python_ast::{self as ast, Constant, Expr, ExprAttribute, ExprCall};
|
||||
use ruff_python_ast::{self as ast, Expr, ExprAttribute, ExprCall};
|
||||
use ruff_text_size::{Ranged, TextRange};
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
|
@ -151,8 +151,8 @@ fn extract_cryptographic_key(
|
|||
|
||||
fn extract_int_argument(call: &ExprCall, name: &str, position: usize) -> Option<(u16, TextRange)> {
|
||||
let argument = call.arguments.find_argument(name, position)?;
|
||||
let Expr::Constant(ast::ExprConstant {
|
||||
value: Constant::Int(i),
|
||||
let Expr::NumberLiteral(ast::ExprNumberLiteral {
|
||||
value: ast::Number::Int(i),
|
||||
..
|
||||
}) = argument
|
||||
else {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use ruff_python_ast::{self as ast, Constant, Expr};
|
||||
use ruff_python_ast::{self as ast, Expr};
|
||||
|
||||
/// Returns `true` if a function call is allowed to use a boolean trap.
|
||||
pub(super) fn is_allowed_func_call(name: &str) -> bool {
|
||||
|
@ -62,14 +62,3 @@ pub(super) fn allow_boolean_trap(func: &Expr) -> bool {
|
|||
|
||||
false
|
||||
}
|
||||
|
||||
/// Returns `true` if an expression is a boolean literal.
|
||||
pub(super) const fn is_boolean(expr: &Expr) -> bool {
|
||||
matches!(
|
||||
&expr,
|
||||
Expr::Constant(ast::ExprConstant {
|
||||
value: Constant::Bool(_),
|
||||
..
|
||||
})
|
||||
)
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ use ruff_python_ast::{Decorator, ParameterWithDefault, Parameters};
|
|||
use ruff_text_size::Ranged;
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::rules::flake8_boolean_trap::helpers::{is_allowed_func_def, is_boolean};
|
||||
use crate::rules::flake8_boolean_trap::helpers::is_allowed_func_def;
|
||||
|
||||
/// ## What it does
|
||||
/// Checks for the use of boolean positional arguments in function definitions,
|
||||
|
@ -117,7 +117,10 @@ pub(crate) fn boolean_default_value_positional_argument(
|
|||
range: _,
|
||||
} in parameters.posonlyargs.iter().chain(¶meters.args)
|
||||
{
|
||||
if default.as_ref().is_some_and(|default| is_boolean(default)) {
|
||||
if default
|
||||
.as_ref()
|
||||
.is_some_and(|default| default.is_boolean_literal_expr())
|
||||
{
|
||||
checker.diagnostics.push(Diagnostic::new(
|
||||
BooleanDefaultValuePositionalArgument,
|
||||
parameter.name.range(),
|
||||
|
|
|
@ -4,7 +4,7 @@ use ruff_python_ast::Expr;
|
|||
use ruff_text_size::Ranged;
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::rules::flake8_boolean_trap::helpers::{allow_boolean_trap, is_boolean};
|
||||
use crate::rules::flake8_boolean_trap::helpers::allow_boolean_trap;
|
||||
|
||||
/// ## What it does
|
||||
/// Checks for boolean positional arguments in function calls.
|
||||
|
@ -49,7 +49,7 @@ pub(crate) fn boolean_positional_value_in_call(checker: &mut Checker, args: &[Ex
|
|||
if allow_boolean_trap(func) {
|
||||
return;
|
||||
}
|
||||
for arg in args.iter().filter(|arg| is_boolean(arg)) {
|
||||
for arg in args.iter().filter(|arg| arg.is_boolean_literal_expr()) {
|
||||
checker
|
||||
.diagnostics
|
||||
.push(Diagnostic::new(BooleanPositionalValueInCall, arg.range()));
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use ruff_python_ast::{self as ast, Constant, Decorator, Expr, ParameterWithDefault, Parameters};
|
||||
use ruff_python_ast::{self as ast, Decorator, Expr, ParameterWithDefault, Parameters};
|
||||
|
||||
use ruff_diagnostics::Diagnostic;
|
||||
use ruff_diagnostics::Violation;
|
||||
|
@ -126,10 +126,7 @@ pub(crate) fn boolean_type_hint_positional_argument(
|
|||
// check for both bool (python class) and 'bool' (string annotation)
|
||||
let hint = match annotation.as_ref() {
|
||||
Expr::Name(name) => &name.id == "bool",
|
||||
Expr::Constant(ast::ExprConstant {
|
||||
value: Constant::Str(ast::StringConstant { value, .. }),
|
||||
..
|
||||
}) => value == "bool",
|
||||
Expr::StringLiteral(ast::ExprStringLiteral { value, .. }) => value == "bool",
|
||||
_ => false,
|
||||
};
|
||||
if !hint || !checker.semantic().is_builtin("bool") {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use ruff_python_ast::{self as ast, Arguments, Constant, Expr, Keyword, Stmt};
|
||||
use ruff_python_ast::{self as ast, Arguments, Expr, Keyword, Stmt};
|
||||
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
|
@ -121,12 +121,12 @@ fn is_abc_class(bases: &[Expr], keywords: &[Keyword], semantic: &SemanticModel)
|
|||
fn is_empty_body(body: &[Stmt]) -> bool {
|
||||
body.iter().all(|stmt| match stmt {
|
||||
Stmt::Pass(_) => true,
|
||||
Stmt::Expr(ast::StmtExpr { value, range: _ }) => match value.as_ref() {
|
||||
Expr::Constant(ast::ExprConstant { value, .. }) => {
|
||||
matches!(value, Constant::Str(..) | Constant::Ellipsis)
|
||||
}
|
||||
_ => false,
|
||||
},
|
||||
Stmt::Expr(ast::StmtExpr { value, range: _ }) => {
|
||||
matches!(
|
||||
value.as_ref(),
|
||||
Expr::StringLiteral(_) | Expr::EllipsisLiteral(_)
|
||||
)
|
||||
}
|
||||
_ => false,
|
||||
})
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use ruff_python_ast::{self as ast, Expr};
|
||||
use ruff_python_ast::Expr;
|
||||
use rustc_hash::FxHashSet;
|
||||
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
|
@ -42,13 +42,13 @@ impl Violation for DuplicateValue {
|
|||
pub(crate) fn duplicate_value(checker: &mut Checker, elts: &Vec<Expr>) {
|
||||
let mut seen_values: FxHashSet<ComparableExpr> = FxHashSet::default();
|
||||
for elt in elts {
|
||||
if let Expr::Constant(ast::ExprConstant { value, .. }) = elt {
|
||||
if elt.is_literal_expr() {
|
||||
let comparable_value: ComparableExpr = elt.into();
|
||||
|
||||
if !seen_values.insert(comparable_value) {
|
||||
checker.diagnostics.push(Diagnostic::new(
|
||||
DuplicateValue {
|
||||
value: checker.generator().constant(value),
|
||||
value: checker.generator().expr(elt),
|
||||
},
|
||||
elt.range(),
|
||||
));
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use crate::fix::edits::pad;
|
||||
use ruff_diagnostics::{AlwaysFixableViolation, Diagnostic, Edit, Fix};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
use ruff_python_ast::{self as ast, Constant, Expr};
|
||||
use ruff_python_ast::{self as ast, Expr};
|
||||
use ruff_python_stdlib::identifiers::{is_identifier, is_mangled_private};
|
||||
use ruff_text_size::Ranged;
|
||||
|
||||
|
@ -66,11 +66,7 @@ pub(crate) fn getattr_with_constant(
|
|||
if obj.is_starred_expr() {
|
||||
return;
|
||||
}
|
||||
let Expr::Constant(ast::ExprConstant {
|
||||
value: Constant::Str(ast::StringConstant { value, .. }),
|
||||
..
|
||||
}) = arg
|
||||
else {
|
||||
let Expr::StringLiteral(ast::ExprStringLiteral { value, .. }) = arg else {
|
||||
return;
|
||||
};
|
||||
if !is_identifier(value) {
|
||||
|
|
|
@ -38,7 +38,7 @@ impl Violation for RaiseLiteral {
|
|||
|
||||
/// B016
|
||||
pub(crate) fn raise_literal(checker: &mut Checker, expr: &Expr) {
|
||||
if expr.is_constant_expr() {
|
||||
if expr.is_literal_expr() {
|
||||
checker
|
||||
.diagnostics
|
||||
.push(Diagnostic::new(RaiseLiteral, expr.range()));
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use ruff_python_ast::{self as ast, Constant, Expr, ExprContext, Identifier, Stmt};
|
||||
use ruff_python_ast::{self as ast, Expr, ExprContext, Identifier, Stmt};
|
||||
use ruff_text_size::{Ranged, TextRange};
|
||||
|
||||
use ruff_diagnostics::{AlwaysFixableViolation, Diagnostic, Edit, Fix};
|
||||
|
@ -80,11 +80,7 @@ pub(crate) fn setattr_with_constant(
|
|||
if obj.is_starred_expr() {
|
||||
return;
|
||||
}
|
||||
let Expr::Constant(ast::ExprConstant {
|
||||
value: Constant::Str(name),
|
||||
..
|
||||
}) = name
|
||||
else {
|
||||
let Expr::StringLiteral(ast::ExprStringLiteral { value: name, .. }) = name else {
|
||||
return;
|
||||
};
|
||||
if !is_identifier(name) {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use itertools::Itertools;
|
||||
use ruff_python_ast::{self as ast, Constant, Expr};
|
||||
use ruff_python_ast::{self as ast, Expr};
|
||||
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
|
@ -68,11 +68,7 @@ pub(crate) fn strip_with_multi_characters(
|
|||
return;
|
||||
}
|
||||
|
||||
let [Expr::Constant(ast::ExprConstant {
|
||||
value: Constant::Str(value),
|
||||
..
|
||||
})] = args
|
||||
else {
|
||||
let [Expr::StringLiteral(ast::ExprStringLiteral { value, .. })] = args else {
|
||||
return;
|
||||
};
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use ruff_python_ast::{self as ast, Constant, Expr};
|
||||
use ruff_python_ast::{self as ast, Expr};
|
||||
|
||||
use ruff_diagnostics::{Diagnostic, Edit, Fix, FixAvailability, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
|
@ -67,11 +67,7 @@ pub(crate) fn unreliable_callable_check(
|
|||
let [obj, attr, ..] = args else {
|
||||
return;
|
||||
};
|
||||
let Expr::Constant(ast::ExprConstant {
|
||||
value: Constant::Str(ast::StringConstant { value, .. }),
|
||||
..
|
||||
}) = attr
|
||||
else {
|
||||
let Expr::StringLiteral(ast::ExprStringLiteral { value, .. }) = attr else {
|
||||
return;
|
||||
};
|
||||
if value != "__call__" {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
use ruff_python_ast::helpers::contains_effect;
|
||||
use ruff_python_ast::{self as ast, Constant, Expr};
|
||||
use ruff_python_ast::Expr;
|
||||
use ruff_text_size::Ranged;
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
|
@ -54,11 +54,7 @@ pub(crate) fn useless_expression(checker: &mut Checker, value: &Expr) {
|
|||
// Ignore strings, to avoid false positives with docstrings.
|
||||
if matches!(
|
||||
value,
|
||||
Expr::FString(_)
|
||||
| Expr::Constant(ast::ExprConstant {
|
||||
value: Constant::Str(..) | Constant::Ellipsis,
|
||||
..
|
||||
})
|
||||
Expr::FString(_) | Expr::StringLiteral(_) | Expr::EllipsisLiteral(_)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
use ruff_python_ast::{self as ast, Constant, Expr, UnaryOp};
|
||||
use ruff_python_ast::{self as ast, Expr, UnaryOp};
|
||||
use ruff_text_size::Ranged;
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
|
@ -79,8 +79,8 @@ pub(crate) fn unnecessary_subscript_reversal(checker: &mut Checker, call: &ast::
|
|||
else {
|
||||
return;
|
||||
};
|
||||
let Expr::Constant(ast::ExprConstant {
|
||||
value: Constant::Int(val),
|
||||
let Expr::NumberLiteral(ast::ExprNumberLiteral {
|
||||
value: ast::Number::Int(val),
|
||||
..
|
||||
}) = operand.as_ref()
|
||||
else {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
use ruff_python_ast::{self as ast, Constant, Expr};
|
||||
use ruff_python_ast::{self as ast, Expr};
|
||||
use ruff_text_size::Ranged;
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
|
@ -75,10 +75,8 @@ pub(crate) fn call_datetime_strptime_without_zone(checker: &mut Checker, call: &
|
|||
}
|
||||
|
||||
// Does the `strptime` call contain a format string with a timezone specifier?
|
||||
if let Some(Expr::Constant(ast::ExprConstant {
|
||||
value: Constant::Str(format),
|
||||
range: _,
|
||||
})) = call.arguments.args.get(1).as_ref()
|
||||
if let Some(Expr::StringLiteral(ast::ExprStringLiteral { value: format, .. })) =
|
||||
call.arguments.args.get(1).as_ref()
|
||||
{
|
||||
if format.contains("%z") {
|
||||
return;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use ruff_python_ast::{self as ast, Arguments, Constant, Expr, Stmt};
|
||||
use ruff_python_ast::{self as ast, Arguments, Expr, Stmt};
|
||||
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
|
@ -80,16 +80,13 @@ pub(crate) fn all_with_model_form(
|
|||
if id != "fields" {
|
||||
continue;
|
||||
}
|
||||
let Expr::Constant(ast::ExprConstant { value, .. }) = value.as_ref() else {
|
||||
continue;
|
||||
};
|
||||
match value {
|
||||
Constant::Str(ast::StringConstant { value, .. }) => {
|
||||
match value.as_ref() {
|
||||
Expr::StringLiteral(ast::ExprStringLiteral { value, .. }) => {
|
||||
if value == "__all__" {
|
||||
return Some(Diagnostic::new(DjangoAllWithModelForm, element.range()));
|
||||
}
|
||||
}
|
||||
Constant::Bytes(ast::BytesConstant { value, .. }) => {
|
||||
Expr::BytesLiteral(ast::ExprBytesLiteral { value, .. }) => {
|
||||
if value == "__all__".as_bytes() {
|
||||
return Some(Diagnostic::new(DjangoAllWithModelForm, element.range()));
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use ruff_python_ast::{self as ast, Arguments, Constant, Expr, ExprContext, Stmt};
|
||||
use ruff_python_ast::{self as ast, Arguments, Expr, ExprContext, Stmt};
|
||||
use ruff_text_size::{Ranged, TextRange};
|
||||
|
||||
use ruff_diagnostics::{Diagnostic, Edit, Fix, FixAvailability, Violation};
|
||||
|
@ -182,10 +182,7 @@ pub(crate) fn string_in_exception(checker: &mut Checker, stmt: &Stmt, exc: &Expr
|
|||
if let Some(first) = args.first() {
|
||||
match first {
|
||||
// Check for string literals.
|
||||
Expr::Constant(ast::ExprConstant {
|
||||
value: Constant::Str(string),
|
||||
..
|
||||
}) => {
|
||||
Expr::StringLiteral(ast::ExprStringLiteral { value: string, .. }) => {
|
||||
if checker.enabled(Rule::RawStringInException) {
|
||||
if string.len() >= checker.settings.flake8_errmsg.max_string_length {
|
||||
let mut diagnostic =
|
||||
|
@ -232,7 +229,7 @@ pub(crate) fn string_in_exception(checker: &mut Checker, stmt: &Stmt, exc: &Expr
|
|||
if let Expr::Attribute(ast::ExprAttribute { value, attr, .. }) =
|
||||
func.as_ref()
|
||||
{
|
||||
if attr == "format" && value.is_constant_expr() {
|
||||
if attr == "format" && value.is_literal_expr() {
|
||||
let mut diagnostic =
|
||||
Diagnostic::new(DotFormatInException, first.range());
|
||||
if let Some(indentation) =
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use ruff_python_ast::{self as ast, Constant, Expr, Operator};
|
||||
use ruff_python_ast::{self as ast, Expr, Operator};
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
|
@ -58,11 +58,7 @@ pub(crate) fn printf_in_gettext_func_call(checker: &mut Checker, args: &[Expr])
|
|||
..
|
||||
}) = &first
|
||||
{
|
||||
if let Expr::Constant(ast::ExprConstant {
|
||||
value: Constant::Str(_),
|
||||
..
|
||||
}) = left.as_ref()
|
||||
{
|
||||
if left.is_string_literal_expr() {
|
||||
checker
|
||||
.diagnostics
|
||||
.push(Diagnostic::new(PrintfInGetTextFuncCall {}, first.range()));
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use ruff_python_ast::{self as ast, Constant, Expr, Operator};
|
||||
use ruff_python_ast::{self as ast, Expr, Operator};
|
||||
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
|
@ -51,18 +51,10 @@ pub(crate) fn explicit(expr: &Expr, locator: &Locator) -> Option<Diagnostic> {
|
|||
if matches!(op, Operator::Add) {
|
||||
if matches!(
|
||||
left.as_ref(),
|
||||
Expr::FString(_)
|
||||
| Expr::Constant(ast::ExprConstant {
|
||||
value: Constant::Str(..) | Constant::Bytes(..),
|
||||
..
|
||||
})
|
||||
Expr::FString(_) | Expr::StringLiteral(_) | Expr::BytesLiteral(_)
|
||||
) && matches!(
|
||||
right.as_ref(),
|
||||
Expr::FString(_)
|
||||
| Expr::Constant(ast::ExprConstant {
|
||||
value: Constant::Str(..) | Constant::Bytes(..),
|
||||
..
|
||||
})
|
||||
Expr::FString(_) | Expr::StringLiteral(_) | Expr::BytesLiteral(_)
|
||||
) && locator.contains_line_break(*range)
|
||||
{
|
||||
return Some(Diagnostic::new(ExplicitStringConcatenation, expr.range()));
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use ruff_diagnostics::{Diagnostic, Edit, Fix};
|
||||
use ruff_python_ast::{self as ast, Arguments, Constant, Expr, Keyword, Operator};
|
||||
use ruff_python_ast::{self as ast, Arguments, Expr, Keyword, Operator};
|
||||
use ruff_python_semantic::analyze::logging;
|
||||
use ruff_python_stdlib::logging::LoggingLevel;
|
||||
use ruff_text_size::Ranged;
|
||||
|
@ -74,7 +74,7 @@ fn check_msg(checker: &mut Checker, msg: &Expr) {
|
|||
Expr::Call(ast::ExprCall { func, .. }) => {
|
||||
if checker.enabled(Rule::LoggingStringFormat) {
|
||||
if let Expr::Attribute(ast::ExprAttribute { value, attr, .. }) = func.as_ref() {
|
||||
if attr == "format" && value.is_constant_expr() {
|
||||
if attr == "format" && value.is_literal_expr() {
|
||||
checker
|
||||
.diagnostics
|
||||
.push(Diagnostic::new(LoggingStringFormat, msg.range()));
|
||||
|
@ -92,11 +92,7 @@ fn check_log_record_attr_clash(checker: &mut Checker, extra: &Keyword) {
|
|||
Expr::Dict(ast::ExprDict { keys, .. }) => {
|
||||
for key in keys {
|
||||
if let Some(key) = &key {
|
||||
if let Expr::Constant(ast::ExprConstant {
|
||||
value: Constant::Str(attr),
|
||||
..
|
||||
}) = key
|
||||
{
|
||||
if let Expr::StringLiteral(ast::ExprStringLiteral { value: attr, .. }) = key {
|
||||
if is_reserved_attr(attr) {
|
||||
checker.diagnostics.push(Diagnostic::new(
|
||||
LoggingExtraAttrClash(attr.to_string()),
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use itertools::Itertools;
|
||||
use ruff_diagnostics::{AlwaysFixableViolation, Diagnostic, Edit, Fix};
|
||||
use ruff_python_ast::{self as ast, Constant, Expr, Keyword};
|
||||
use ruff_python_ast::{self as ast, Expr, Keyword};
|
||||
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
use ruff_text_size::Ranged;
|
||||
|
@ -96,7 +96,7 @@ pub(crate) fn unnecessary_dict_kwargs(checker: &mut Checker, expr: &Expr, kwargs
|
|||
.iter()
|
||||
.zip(values.iter())
|
||||
.map(|(kwarg, value)| {
|
||||
format!("{}={}", kwarg.value, checker.locator().slice(value.range()))
|
||||
format!("{}={}", kwarg, checker.locator().slice(value.range()))
|
||||
})
|
||||
.join(", "),
|
||||
kw.range(),
|
||||
|
@ -108,12 +108,8 @@ pub(crate) fn unnecessary_dict_kwargs(checker: &mut Checker, expr: &Expr, kwargs
|
|||
}
|
||||
|
||||
/// Return `Some` if a key is a valid keyword argument name, or `None` otherwise.
|
||||
fn as_kwarg(key: &Expr) -> Option<&ast::StringConstant> {
|
||||
if let Expr::Constant(ast::ExprConstant {
|
||||
value: Constant::Str(value),
|
||||
..
|
||||
}) = key
|
||||
{
|
||||
fn as_kwarg(key: &Expr) -> Option<&str> {
|
||||
if let Expr::StringLiteral(ast::ExprStringLiteral { value, .. }) = key {
|
||||
if is_identifier(value) {
|
||||
return Some(value);
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use ruff_diagnostics::Diagnostic;
|
||||
use ruff_diagnostics::{AlwaysFixableViolation, Fix};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
use ruff_python_ast::{self as ast, Constant, Expr};
|
||||
use ruff_python_ast::{self as ast, Expr};
|
||||
use ruff_text_size::Ranged;
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
|
@ -65,8 +65,8 @@ pub(crate) fn unnecessary_range_start(checker: &mut Checker, call: &ast::ExprCal
|
|||
};
|
||||
|
||||
// Verify that the `start` argument is the literal `0`.
|
||||
let Expr::Constant(ast::ExprConstant {
|
||||
value: Constant::Int(value),
|
||||
let Expr::NumberLiteral(ast::ExprNumberLiteral {
|
||||
value: ast::Number::Int(value),
|
||||
..
|
||||
}) = start
|
||||
else {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use ruff_python_ast::Expr;
|
||||
use ruff_python_ast::ExprStringLiteral;
|
||||
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
|
@ -36,8 +36,8 @@ impl Violation for DocstringInStub {
|
|||
}
|
||||
|
||||
/// PYI021
|
||||
pub(crate) fn docstring_in_stubs(checker: &mut Checker, docstring: Option<&Expr>) {
|
||||
if let Some(docstr) = &docstring {
|
||||
pub(crate) fn docstring_in_stubs(checker: &mut Checker, docstring: Option<&ExprStringLiteral>) {
|
||||
if let Some(docstr) = docstring {
|
||||
checker
|
||||
.diagnostics
|
||||
.push(Diagnostic::new(DocstringInStub, docstr.range()));
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use ruff_diagnostics::{Diagnostic, Fix, FixAvailability, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
use ruff_python_ast::{Constant, Expr, ExprConstant, Stmt, StmtExpr};
|
||||
use ruff_python_ast::{Stmt, StmtExpr};
|
||||
use ruff_text_size::Ranged;
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
|
@ -54,13 +54,7 @@ pub(crate) fn ellipsis_in_non_empty_class_body(checker: &mut Checker, body: &[St
|
|||
continue;
|
||||
};
|
||||
|
||||
if matches!(
|
||||
value.as_ref(),
|
||||
Expr::Constant(ExprConstant {
|
||||
value: Constant::Ellipsis,
|
||||
..
|
||||
})
|
||||
) {
|
||||
if value.is_ellipsis_literal_expr() {
|
||||
let mut diagnostic = Diagnostic::new(EllipsisInNonEmptyClassBody, stmt.range());
|
||||
let edit =
|
||||
fix::edits::delete_stmt(stmt, Some(stmt), checker.locator(), checker.indexer());
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use ruff_diagnostics::{AlwaysFixableViolation, Diagnostic, Edit, Fix};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
use ruff_python_ast::helpers::is_docstring_stmt;
|
||||
use ruff_python_ast::{self as ast, Expr, Stmt};
|
||||
use ruff_python_ast::{self as ast, Stmt};
|
||||
use ruff_text_size::Ranged;
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
|
@ -60,10 +60,8 @@ pub(crate) fn non_empty_stub_body(checker: &mut Checker, body: &[Stmt]) {
|
|||
|
||||
// Ignore `...` (the desired case).
|
||||
if let Stmt::Expr(ast::StmtExpr { value, range: _ }) = stmt {
|
||||
if let Expr::Constant(ast::ExprConstant { value, .. }) = value.as_ref() {
|
||||
if value.is_ellipsis() {
|
||||
return;
|
||||
}
|
||||
if value.is_ellipsis_literal_expr() {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
use rustc_hash::FxHashSet;
|
||||
use std::fmt;
|
||||
|
||||
use ast::Constant;
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
use ruff_python_ast::{self as ast, Expr};
|
||||
|
@ -147,14 +146,15 @@ fn match_builtin_type(expr: &Expr, semantic: &SemanticModel) -> Option<ExprType>
|
|||
/// Return the [`ExprType`] of an [`Expr]` if it is a constant (e.g., an `int`, like `1`, or a
|
||||
/// `bool`, like `True`).
|
||||
fn match_constant_type(expr: &Expr) -> Option<ExprType> {
|
||||
let constant = expr.as_constant_expr()?;
|
||||
let result = match constant.value {
|
||||
Constant::Bool(_) => ExprType::Bool,
|
||||
Constant::Str(_) => ExprType::Str,
|
||||
Constant::Bytes(_) => ExprType::Bytes,
|
||||
Constant::Int(_) => ExprType::Int,
|
||||
Constant::Float(_) => ExprType::Float,
|
||||
Constant::Complex { .. } => ExprType::Complex,
|
||||
let result = match expr {
|
||||
Expr::BooleanLiteral(_) => ExprType::Bool,
|
||||
Expr::StringLiteral(_) => ExprType::Str,
|
||||
Expr::BytesLiteral(_) => ExprType::Bytes,
|
||||
Expr::NumberLiteral(ast::ExprNumberLiteral { value, .. }) => match value {
|
||||
ast::Number::Int(_) => ExprType::Int,
|
||||
ast::Number::Float(_) => ExprType::Float,
|
||||
ast::Number::Complex { .. } => ExprType::Complex,
|
||||
},
|
||||
_ => return None,
|
||||
};
|
||||
Some(result)
|
||||
|
|
|
@ -2,8 +2,7 @@ use ruff_diagnostics::{AlwaysFixableViolation, Diagnostic, Edit, Fix, Violation}
|
|||
use ruff_macros::{derive_message_formats, violation};
|
||||
use ruff_python_ast::call_path::CallPath;
|
||||
use ruff_python_ast::{
|
||||
self as ast, Arguments, Constant, Expr, Operator, ParameterWithDefault, Parameters, Stmt,
|
||||
UnaryOp,
|
||||
self as ast, Arguments, Expr, Operator, ParameterWithDefault, Parameters, Stmt, UnaryOp,
|
||||
};
|
||||
use ruff_python_semantic::{ScopeKind, SemanticModel};
|
||||
use ruff_source_file::Locator;
|
||||
|
@ -282,7 +281,12 @@ fn is_valid_default_value_with_annotation(
|
|||
semantic: &SemanticModel,
|
||||
) -> bool {
|
||||
match default {
|
||||
Expr::Constant(_) => {
|
||||
Expr::StringLiteral(_)
|
||||
| Expr::BytesLiteral(_)
|
||||
| Expr::NumberLiteral(_)
|
||||
| Expr::BooleanLiteral(_)
|
||||
| Expr::NoneLiteral(_)
|
||||
| Expr::EllipsisLiteral(_) => {
|
||||
return true;
|
||||
}
|
||||
Expr::List(ast::ExprList { elts, .. })
|
||||
|
@ -314,10 +318,7 @@ fn is_valid_default_value_with_annotation(
|
|||
}) => {
|
||||
match operand.as_ref() {
|
||||
// Ex) `-1`, `-3.14`, `2j`
|
||||
Expr::Constant(ast::ExprConstant {
|
||||
value: Constant::Int(..) | Constant::Float(..) | Constant::Complex { .. },
|
||||
..
|
||||
}) => return true,
|
||||
Expr::NumberLiteral(_) => return true,
|
||||
// Ex) `-math.inf`, `-math.pi`, etc.
|
||||
Expr::Attribute(_) => {
|
||||
if semantic
|
||||
|
@ -338,14 +339,14 @@ fn is_valid_default_value_with_annotation(
|
|||
range: _,
|
||||
}) => {
|
||||
// Ex) `1 + 2j`, `1 - 2j`, `-1 - 2j`, `-1 + 2j`
|
||||
if let Expr::Constant(ast::ExprConstant {
|
||||
value: Constant::Complex { .. },
|
||||
if let Expr::NumberLiteral(ast::ExprNumberLiteral {
|
||||
value: ast::Number::Complex { .. },
|
||||
..
|
||||
}) = right.as_ref()
|
||||
{
|
||||
// Ex) `1 + 2j`, `1 - 2j`
|
||||
if let Expr::Constant(ast::ExprConstant {
|
||||
value: Constant::Int(..) | Constant::Float(..),
|
||||
if let Expr::NumberLiteral(ast::ExprNumberLiteral {
|
||||
value: ast::Number::Int(..) | ast::Number::Float(..),
|
||||
..
|
||||
}) = left.as_ref()
|
||||
{
|
||||
|
@ -357,8 +358,8 @@ fn is_valid_default_value_with_annotation(
|
|||
}) = left.as_ref()
|
||||
{
|
||||
// Ex) `-1 + 2j`, `-1 - 2j`
|
||||
if let Expr::Constant(ast::ExprConstant {
|
||||
value: Constant::Int(..) | Constant::Float(..),
|
||||
if let Expr::NumberLiteral(ast::ExprNumberLiteral {
|
||||
value: ast::Number::Int(..) | ast::Number::Float(..),
|
||||
..
|
||||
}) = operand.as_ref()
|
||||
{
|
||||
|
@ -393,13 +394,7 @@ fn is_valid_pep_604_union(annotation: &Expr) -> bool {
|
|||
right,
|
||||
range: _,
|
||||
}) => is_valid_pep_604_union_member(left) && is_valid_pep_604_union_member(right),
|
||||
Expr::Name(_)
|
||||
| Expr::Subscript(_)
|
||||
| Expr::Attribute(_)
|
||||
| Expr::Constant(ast::ExprConstant {
|
||||
value: Constant::None,
|
||||
..
|
||||
}) => true,
|
||||
Expr::Name(_) | Expr::Subscript(_) | Expr::Attribute(_) | Expr::NoneLiteral(_) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
@ -427,10 +422,8 @@ fn is_valid_default_value_without_annotation(default: &Expr) -> bool {
|
|||
| Expr::Name(_)
|
||||
| Expr::Attribute(_)
|
||||
| Expr::Subscript(_)
|
||||
| Expr::Constant(ast::ExprConstant {
|
||||
value: Constant::Ellipsis | Constant::None,
|
||||
..
|
||||
})
|
||||
| Expr::EllipsisLiteral(_)
|
||||
| Expr::NoneLiteral(_)
|
||||
) || is_valid_pep_604_union(default)
|
||||
}
|
||||
|
||||
|
@ -499,14 +492,8 @@ fn is_enum(arguments: Option<&Arguments>, semantic: &SemanticModel) -> bool {
|
|||
/// valid type alias. In particular, this function checks for uses of `typing.Any`, `None`,
|
||||
/// parameterized generics, and PEP 604-style unions.
|
||||
fn is_annotatable_type_alias(value: &Expr, semantic: &SemanticModel) -> bool {
|
||||
matches!(
|
||||
value,
|
||||
Expr::Subscript(_)
|
||||
| Expr::Constant(ast::ExprConstant {
|
||||
value: Constant::None,
|
||||
..
|
||||
}),
|
||||
) || is_valid_pep_604_union(value)
|
||||
matches!(value, Expr::Subscript(_) | Expr::NoneLiteral(_))
|
||||
|| is_valid_pep_604_union(value)
|
||||
|| semantic.match_typing_expr(value, "Any")
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use ruff_python_ast::{self as ast, Constant, Expr};
|
||||
use ruff_python_ast::{self as ast, Expr};
|
||||
|
||||
use ruff_diagnostics::{AlwaysFixableViolation, Diagnostic, Edit, Fix};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
|
@ -51,14 +51,8 @@ pub(crate) fn string_or_bytes_too_long(checker: &mut Checker, expr: &Expr) {
|
|||
}
|
||||
|
||||
let length = match expr {
|
||||
Expr::Constant(ast::ExprConstant {
|
||||
value: Constant::Str(s),
|
||||
..
|
||||
}) => s.chars().count(),
|
||||
Expr::Constant(ast::ExprConstant {
|
||||
value: Constant::Bytes(bytes),
|
||||
..
|
||||
}) => bytes.len(),
|
||||
Expr::StringLiteral(ast::ExprStringLiteral { value, .. }) => value.chars().count(),
|
||||
Expr::BytesLiteral(ast::ExprBytesLiteral { value, .. }) => value.len(),
|
||||
_ => return,
|
||||
};
|
||||
if length <= 50 {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use ruff_python_ast::{self as ast, CmpOp, Constant, Expr};
|
||||
use ruff_python_ast::{self as ast, CmpOp, Expr};
|
||||
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
|
@ -123,11 +123,7 @@ pub(crate) fn unrecognized_platform(checker: &mut Checker, test: &Expr) {
|
|||
return;
|
||||
}
|
||||
|
||||
if let Expr::Constant(ast::ExprConstant {
|
||||
value: Constant::Str(ast::StringConstant { value, .. }),
|
||||
..
|
||||
}) = right
|
||||
{
|
||||
if let Expr::StringLiteral(ast::ExprStringLiteral { value, .. }) = right {
|
||||
// Other values are possible but we don't need them right now.
|
||||
// This protects against typos.
|
||||
if checker.enabled(Rule::UnrecognizedPlatformName) {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
use ruff_python_ast::helpers::map_subscript;
|
||||
use ruff_python_ast::{self as ast, CmpOp, Constant, Expr, Int};
|
||||
use ruff_python_ast::{self as ast, CmpOp, Expr, Int};
|
||||
use ruff_text_size::Ranged;
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
|
@ -241,8 +241,8 @@ impl ExpectedComparator {
|
|||
step: None,
|
||||
..
|
||||
}) => {
|
||||
if let Expr::Constant(ast::ExprConstant {
|
||||
value: Constant::Int(upper),
|
||||
if let Expr::NumberLiteral(ast::ExprNumberLiteral {
|
||||
value: ast::Number::Int(upper),
|
||||
..
|
||||
}) = upper.as_ref()
|
||||
{
|
||||
|
@ -254,8 +254,8 @@ impl ExpectedComparator {
|
|||
}
|
||||
}
|
||||
}
|
||||
Expr::Constant(ast::ExprConstant {
|
||||
value: Constant::Int(Int::ZERO),
|
||||
Expr::NumberLiteral(ast::ExprNumberLiteral {
|
||||
value: ast::Number::Int(Int::ZERO),
|
||||
..
|
||||
}) => {
|
||||
return Some(ExpectedComparator::MajorDigit);
|
||||
|
@ -271,8 +271,8 @@ impl ExpectedComparator {
|
|||
fn is_int_constant(expr: &Expr) -> bool {
|
||||
matches!(
|
||||
expr,
|
||||
Expr::Constant(ast::ExprConstant {
|
||||
value: ast::Constant::Int(_),
|
||||
Expr::NumberLiteral(ast::ExprNumberLiteral {
|
||||
value: ast::Number::Int(_),
|
||||
..
|
||||
})
|
||||
)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use ruff_python_ast::{self as ast, Constant, Decorator, Expr, Keyword};
|
||||
use ruff_python_ast::{self as ast, Decorator, Expr, Keyword};
|
||||
|
||||
use ruff_python_ast::call_path::collect_call_path;
|
||||
use ruff_python_ast::helpers::map_callable;
|
||||
|
@ -44,11 +44,7 @@ pub(super) fn is_pytest_parametrize(decorator: &Decorator, semantic: &SemanticMo
|
|||
}
|
||||
|
||||
pub(super) fn keyword_is_literal(keyword: &Keyword, literal: &str) -> bool {
|
||||
if let Expr::Constant(ast::ExprConstant {
|
||||
value: Constant::Str(ast::StringConstant { value, .. }),
|
||||
..
|
||||
}) = &keyword.value
|
||||
{
|
||||
if let Expr::StringLiteral(ast::ExprStringLiteral { value, .. }) = &keyword.value {
|
||||
value == literal
|
||||
} else {
|
||||
false
|
||||
|
@ -57,11 +53,8 @@ pub(super) fn keyword_is_literal(keyword: &Keyword, literal: &str) -> bool {
|
|||
|
||||
pub(super) fn is_empty_or_null_string(expr: &Expr) -> bool {
|
||||
match expr {
|
||||
Expr::Constant(ast::ExprConstant {
|
||||
value: Constant::Str(string),
|
||||
..
|
||||
}) => string.is_empty(),
|
||||
Expr::Constant(constant) if constant.value.is_none() => true,
|
||||
Expr::StringLiteral(ast::ExprStringLiteral { value, .. }) => value.is_empty(),
|
||||
Expr::NoneLiteral(_) => true,
|
||||
Expr::FString(ast::ExprFString { values, .. }) => {
|
||||
values.iter().all(is_empty_or_null_string)
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@ use ruff_macros::{derive_message_formats, violation};
|
|||
use ruff_python_ast::comparable::ComparableExpr;
|
||||
use ruff_python_ast::parenthesize::parenthesized_range;
|
||||
use ruff_python_ast::AstNode;
|
||||
use ruff_python_ast::{self as ast, Arguments, Constant, Decorator, Expr, ExprContext};
|
||||
use ruff_python_ast::{self as ast, Arguments, Decorator, Expr, ExprContext};
|
||||
use ruff_python_codegen::Generator;
|
||||
use ruff_python_trivia::CommentRanges;
|
||||
use ruff_python_trivia::{SimpleTokenKind, SimpleTokenizer};
|
||||
|
@ -248,37 +248,22 @@ impl Violation for PytestDuplicateParametrizeTestCases {
|
|||
}
|
||||
|
||||
fn elts_to_csv(elts: &[Expr], generator: Generator) -> Option<String> {
|
||||
let all_literals = elts.iter().all(|expr| {
|
||||
matches!(
|
||||
expr,
|
||||
Expr::Constant(ast::ExprConstant {
|
||||
value: Constant::Str(_),
|
||||
..
|
||||
})
|
||||
)
|
||||
});
|
||||
|
||||
if !all_literals {
|
||||
if !elts.iter().all(Expr::is_string_literal_expr) {
|
||||
return None;
|
||||
}
|
||||
|
||||
let node = Expr::Constant(ast::ExprConstant {
|
||||
value: elts
|
||||
.iter()
|
||||
.fold(String::new(), |mut acc, elt| {
|
||||
if let Expr::Constant(ast::ExprConstant {
|
||||
value: Constant::Str(ast::StringConstant { value, .. }),
|
||||
..
|
||||
}) = elt
|
||||
{
|
||||
if !acc.is_empty() {
|
||||
acc.push(',');
|
||||
}
|
||||
acc.push_str(value.as_str());
|
||||
let node = Expr::StringLiteral(ast::ExprStringLiteral {
|
||||
value: elts.iter().fold(String::new(), |mut acc, elt| {
|
||||
if let Expr::StringLiteral(ast::ExprStringLiteral { value, .. }) = elt {
|
||||
if !acc.is_empty() {
|
||||
acc.push(',');
|
||||
}
|
||||
acc
|
||||
})
|
||||
.into(),
|
||||
acc.push_str(value.as_str());
|
||||
}
|
||||
acc
|
||||
}),
|
||||
unicode: false,
|
||||
implicit_concatenated: false,
|
||||
range: TextRange::default(),
|
||||
});
|
||||
Some(generator.expr(&node))
|
||||
|
@ -317,10 +302,7 @@ fn check_names(checker: &mut Checker, decorator: &Decorator, expr: &Expr) {
|
|||
let names_type = checker.settings.flake8_pytest_style.parametrize_names_type;
|
||||
|
||||
match expr {
|
||||
Expr::Constant(ast::ExprConstant {
|
||||
value: Constant::Str(string),
|
||||
..
|
||||
}) => {
|
||||
Expr::StringLiteral(ast::ExprStringLiteral { value: string, .. }) => {
|
||||
let names = split_names(string);
|
||||
if names.len() > 1 {
|
||||
match names_type {
|
||||
|
@ -342,8 +324,10 @@ fn check_names(checker: &mut Checker, decorator: &Decorator, expr: &Expr) {
|
|||
elts: names
|
||||
.iter()
|
||||
.map(|name| {
|
||||
Expr::Constant(ast::ExprConstant {
|
||||
value: (*name).to_string().into(),
|
||||
Expr::StringLiteral(ast::ExprStringLiteral {
|
||||
value: (*name).to_string(),
|
||||
unicode: false,
|
||||
implicit_concatenated: false,
|
||||
range: TextRange::default(),
|
||||
})
|
||||
})
|
||||
|
@ -375,8 +359,10 @@ fn check_names(checker: &mut Checker, decorator: &Decorator, expr: &Expr) {
|
|||
elts: names
|
||||
.iter()
|
||||
.map(|name| {
|
||||
Expr::Constant(ast::ExprConstant {
|
||||
value: (*name).to_string().into(),
|
||||
Expr::StringLiteral(ast::ExprStringLiteral {
|
||||
value: (*name).to_string(),
|
||||
unicode: false,
|
||||
implicit_concatenated: false,
|
||||
range: TextRange::default(),
|
||||
})
|
||||
})
|
||||
|
@ -495,15 +481,12 @@ fn check_values(checker: &mut Checker, names: &Expr, values: &Expr) {
|
|||
.flake8_pytest_style
|
||||
.parametrize_values_row_type;
|
||||
|
||||
let is_multi_named = if let Expr::Constant(ast::ExprConstant {
|
||||
value: Constant::Str(string),
|
||||
..
|
||||
}) = &names
|
||||
{
|
||||
split_names(string).len() > 1
|
||||
} else {
|
||||
true
|
||||
};
|
||||
let is_multi_named =
|
||||
if let Expr::StringLiteral(ast::ExprStringLiteral { value: string, .. }) = &names {
|
||||
split_names(string).len() > 1
|
||||
} else {
|
||||
true
|
||||
};
|
||||
|
||||
match values {
|
||||
Expr::List(ast::ExprList { elts, .. }) => {
|
||||
|
|
|
@ -2,7 +2,7 @@ use std::hash::BuildHasherDefault;
|
|||
|
||||
use anyhow::{anyhow, bail, Result};
|
||||
use ruff_python_ast::{
|
||||
self as ast, Arguments, CmpOp, Constant, Expr, ExprContext, Identifier, Keyword, Stmt, UnaryOp,
|
||||
self as ast, Arguments, CmpOp, Expr, ExprContext, Identifier, Keyword, Stmt, UnaryOp,
|
||||
};
|
||||
use ruff_text_size::TextRange;
|
||||
use rustc_hash::FxHashMap;
|
||||
|
@ -368,8 +368,7 @@ impl UnittestAssert {
|
|||
} else {
|
||||
CmpOp::IsNot
|
||||
};
|
||||
let node = Expr::Constant(ast::ExprConstant {
|
||||
value: Constant::None,
|
||||
let node = Expr::NoneLiteral(ast::ExprNoneLiteral {
|
||||
range: TextRange::default(),
|
||||
});
|
||||
let expr = compare(expr, cmp_op, &node);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use ruff_python_ast as ast;
|
||||
use ruff_python_ast::{Expr, Stmt};
|
||||
use ruff_python_ast::Stmt;
|
||||
use ruff_text_size::{Ranged, TextSize};
|
||||
|
||||
use ruff_source_file::{Locator, UniversalNewlines};
|
||||
|
@ -8,12 +8,9 @@ use ruff_source_file::{Locator, UniversalNewlines};
|
|||
/// non-`None` value.
|
||||
pub(super) fn result_exists(returns: &[&ast::StmtReturn]) -> bool {
|
||||
returns.iter().any(|stmt| {
|
||||
stmt.value.as_deref().is_some_and(|value| {
|
||||
!matches!(
|
||||
value,
|
||||
Expr::Constant(constant) if constant.value.is_none()
|
||||
)
|
||||
})
|
||||
stmt.value
|
||||
.as_deref()
|
||||
.is_some_and(|value| !value.is_none_literal_expr())
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use ruff_python_ast::{self as ast, Arguments, Constant, Expr};
|
||||
use ruff_python_ast::{self as ast, Arguments, Expr};
|
||||
use ruff_text_size::{Ranged, TextRange};
|
||||
|
||||
use crate::fix::snippet::SourceCodeSnippet;
|
||||
|
@ -139,11 +139,7 @@ pub(crate) fn use_capital_environment_variables(checker: &mut Checker, expr: &Ex
|
|||
let Some(arg) = args.get(0) else {
|
||||
return;
|
||||
};
|
||||
let Expr::Constant(ast::ExprConstant {
|
||||
value: Constant::Str(ast::StringConstant { value: env_var, .. }),
|
||||
..
|
||||
}) = arg
|
||||
else {
|
||||
let Expr::StringLiteral(ast::ExprStringLiteral { value: env_var, .. }) = arg else {
|
||||
return;
|
||||
};
|
||||
if !checker
|
||||
|
@ -195,14 +191,10 @@ fn check_os_environ_subscript(checker: &mut Checker, expr: &Expr) {
|
|||
if id != "os" || attr != "environ" {
|
||||
return;
|
||||
}
|
||||
let Expr::Constant(ast::ExprConstant {
|
||||
value:
|
||||
Constant::Str(ast::StringConstant {
|
||||
value: env_var,
|
||||
unicode,
|
||||
..
|
||||
}),
|
||||
range: _,
|
||||
let Expr::StringLiteral(ast::ExprStringLiteral {
|
||||
value: env_var,
|
||||
unicode,
|
||||
..
|
||||
}) = slice.as_ref()
|
||||
else {
|
||||
return;
|
||||
|
@ -224,12 +216,10 @@ fn check_os_environ_subscript(checker: &mut Checker, expr: &Expr) {
|
|||
},
|
||||
slice.range(),
|
||||
);
|
||||
let node = ast::ExprConstant {
|
||||
value: ast::Constant::Str(ast::StringConstant {
|
||||
value: capital_env_var,
|
||||
unicode: *unicode,
|
||||
implicit_concatenated: false,
|
||||
}),
|
||||
let node = ast::ExprStringLiteral {
|
||||
value: capital_env_var,
|
||||
unicode: *unicode,
|
||||
implicit_concatenated: false,
|
||||
range: TextRange::default(),
|
||||
};
|
||||
let new_env_var = node.into();
|
||||
|
@ -265,7 +255,7 @@ pub(crate) fn dict_get_with_none_default(checker: &mut Checker, expr: &Expr) {
|
|||
let Some(key) = args.get(0) else {
|
||||
return;
|
||||
};
|
||||
if !matches!(key, Expr::Constant(_) | Expr::Name(_)) {
|
||||
if !(key.is_literal_expr() || key.is_name_expr()) {
|
||||
return;
|
||||
}
|
||||
let Some(default) = args.get(1) else {
|
||||
|
|
|
@ -7,7 +7,7 @@ use log::error;
|
|||
use ruff_diagnostics::{Diagnostic, Edit, Fix, FixAvailability, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
use ruff_python_ast::AnyNodeRef;
|
||||
use ruff_python_ast::{self as ast, whitespace, Constant, ElifElseClause, Expr, Stmt};
|
||||
use ruff_python_ast::{self as ast, whitespace, ElifElseClause, Expr, Stmt};
|
||||
use ruff_python_codegen::Stylist;
|
||||
use ruff_python_semantic::analyze::typing::{is_sys_version_block, is_type_checking_block};
|
||||
use ruff_python_trivia::{SimpleTokenKind, SimpleTokenizer};
|
||||
|
@ -212,13 +212,7 @@ fn nested_if_body(stmt_if: &ast::StmtIf) -> Option<NestedIf> {
|
|||
}
|
||||
|
||||
// Allow `if True:` and `if False:` statements.
|
||||
if matches!(
|
||||
test,
|
||||
Expr::Constant(ast::ExprConstant {
|
||||
value: Constant::Bool(..),
|
||||
..
|
||||
})
|
||||
) {
|
||||
if test.is_boolean_literal_expr() {
|
||||
return None;
|
||||
}
|
||||
|
||||
|
@ -259,10 +253,8 @@ fn is_main_check(expr: &Expr) -> bool {
|
|||
{
|
||||
if let Expr::Name(ast::ExprName { id, .. }) = left.as_ref() {
|
||||
if id == "__name__" {
|
||||
if let [Expr::Constant(ast::ExprConstant {
|
||||
value: Constant::Str(ast::StringConstant { value, .. }),
|
||||
..
|
||||
})] = comparators.as_slice()
|
||||
if let [Expr::StringLiteral(ast::ExprStringLiteral { value, .. })] =
|
||||
comparators.as_slice()
|
||||
{
|
||||
if value == "__main__" {
|
||||
return true;
|
||||
|
|
|
@ -2,7 +2,7 @@ use rustc_hash::FxHashSet;
|
|||
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
use ruff_python_ast::comparable::ComparableConstant;
|
||||
use ruff_python_ast::comparable::ComparableExpr;
|
||||
use ruff_python_ast::helpers::contains_effect;
|
||||
use ruff_python_ast::{self as ast, CmpOp, ElifElseClause, Expr, Stmt};
|
||||
use ruff_python_semantic::analyze::typing::{is_sys_version_block, is_type_checking_block};
|
||||
|
@ -67,12 +67,12 @@ pub(crate) fn if_else_block_instead_of_dict_lookup(checker: &mut Checker, stmt_i
|
|||
if ops != &[CmpOp::Eq] {
|
||||
return;
|
||||
}
|
||||
let [Expr::Constant(ast::ExprConstant {
|
||||
value: constant, ..
|
||||
})] = comparators.as_slice()
|
||||
else {
|
||||
let [expr] = comparators.as_slice() else {
|
||||
return;
|
||||
};
|
||||
if !expr.is_literal_expr() {
|
||||
return;
|
||||
}
|
||||
let [Stmt::Return(ast::StmtReturn { value, range: _ })] = body.as_slice() else {
|
||||
return;
|
||||
};
|
||||
|
@ -94,8 +94,9 @@ pub(crate) fn if_else_block_instead_of_dict_lookup(checker: &mut Checker, stmt_i
|
|||
return;
|
||||
}
|
||||
|
||||
let mut constants: FxHashSet<ComparableConstant> = FxHashSet::default();
|
||||
constants.insert(constant.into());
|
||||
// The `expr` was checked to be a literal above, so this is safe.
|
||||
let mut literals: FxHashSet<ComparableExpr> = FxHashSet::default();
|
||||
literals.insert(expr.into());
|
||||
|
||||
for clause in elif_else_clauses {
|
||||
let ElifElseClause { test, body, .. } = clause;
|
||||
|
@ -129,12 +130,12 @@ pub(crate) fn if_else_block_instead_of_dict_lookup(checker: &mut Checker, stmt_i
|
|||
if id != target || ops != &[CmpOp::Eq] {
|
||||
return;
|
||||
}
|
||||
let [Expr::Constant(ast::ExprConstant {
|
||||
value: constant, ..
|
||||
})] = comparators.as_slice()
|
||||
else {
|
||||
let [expr] = comparators.as_slice() else {
|
||||
return;
|
||||
};
|
||||
if !expr.is_literal_expr() {
|
||||
return;
|
||||
}
|
||||
|
||||
if value.as_ref().is_some_and(|value| {
|
||||
contains_effect(value, |id| checker.semantic().is_builtin(id))
|
||||
|
@ -142,7 +143,8 @@ pub(crate) fn if_else_block_instead_of_dict_lookup(checker: &mut Checker, stmt_i
|
|||
return;
|
||||
};
|
||||
|
||||
constants.insert(constant.into());
|
||||
// The `expr` was checked to be a literal above, so this is safe.
|
||||
literals.insert(expr.into());
|
||||
}
|
||||
// Different `elif`
|
||||
_ => {
|
||||
|
@ -151,7 +153,7 @@ pub(crate) fn if_else_block_instead_of_dict_lookup(checker: &mut Checker, stmt_i
|
|||
}
|
||||
}
|
||||
|
||||
if constants.len() < 3 {
|
||||
if literals.len() < 3 {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use ruff_diagnostics::{Diagnostic, Edit, Fix, FixAvailability, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
use ruff_python_ast::{self as ast, Arguments, Constant, ElifElseClause, Expr, ExprContext, Stmt};
|
||||
use ruff_python_ast::{self as ast, Arguments, ElifElseClause, Expr, ExprContext, Stmt};
|
||||
use ruff_python_semantic::analyze::typing::{is_sys_version_block, is_type_checking_block};
|
||||
use ruff_text_size::{Ranged, TextRange};
|
||||
|
||||
|
@ -176,10 +176,7 @@ fn is_one_line_return_bool(stmts: &[Stmt]) -> Option<Bool> {
|
|||
let Stmt::Return(ast::StmtReturn { value, range: _ }) = stmt else {
|
||||
return None;
|
||||
};
|
||||
let Some(Expr::Constant(ast::ExprConstant { value, .. })) = value.as_deref() else {
|
||||
return None;
|
||||
};
|
||||
let Constant::Bool(value) = value else {
|
||||
let Some(Expr::BooleanLiteral(ast::ExprBooleanLiteral { value, .. })) = value.as_deref() else {
|
||||
return None;
|
||||
};
|
||||
Some((*value).into())
|
||||
|
|
|
@ -3,7 +3,7 @@ use ruff_macros::{derive_message_formats, violation};
|
|||
use ruff_python_ast::helpers::any_over_expr;
|
||||
use ruff_python_ast::traversal;
|
||||
use ruff_python_ast::{
|
||||
self as ast, Arguments, CmpOp, Comprehension, Constant, Expr, ExprContext, Stmt, UnaryOp,
|
||||
self as ast, Arguments, CmpOp, Comprehension, Expr, ExprContext, Stmt, UnaryOp,
|
||||
};
|
||||
use ruff_python_codegen::Generator;
|
||||
use ruff_text_size::{Ranged, TextRange};
|
||||
|
@ -280,11 +280,7 @@ fn match_loop(stmt: &Stmt) -> Option<Loop> {
|
|||
let Some(value) = value else {
|
||||
return None;
|
||||
};
|
||||
let Expr::Constant(ast::ExprConstant {
|
||||
value: Constant::Bool(value),
|
||||
..
|
||||
}) = value.as_ref()
|
||||
else {
|
||||
let Expr::BooleanLiteral(ast::ExprBooleanLiteral { value, .. }) = value.as_ref() else {
|
||||
return None;
|
||||
};
|
||||
|
||||
|
@ -319,9 +315,8 @@ fn match_else_return(stmt: &Stmt) -> Option<Terminal> {
|
|||
else {
|
||||
return None;
|
||||
};
|
||||
let Expr::Constant(ast::ExprConstant {
|
||||
value: Constant::Bool(next_value),
|
||||
..
|
||||
let Expr::BooleanLiteral(ast::ExprBooleanLiteral {
|
||||
value: next_value, ..
|
||||
}) = next_value.as_ref()
|
||||
else {
|
||||
return None;
|
||||
|
@ -362,9 +357,8 @@ fn match_sibling_return<'a>(stmt: &'a Stmt, sibling: &'a Stmt) -> Option<Termina
|
|||
else {
|
||||
return None;
|
||||
};
|
||||
let Expr::Constant(ast::ExprConstant {
|
||||
value: Constant::Bool(next_value),
|
||||
..
|
||||
let Expr::BooleanLiteral(ast::ExprBooleanLiteral {
|
||||
value: next_value, ..
|
||||
}) = next_value.as_ref()
|
||||
else {
|
||||
return None;
|
||||
|
|
|
@ -2,7 +2,7 @@ use ruff_diagnostics::{Diagnostic, Edit, Fix, FixAvailability, Violation};
|
|||
use ruff_macros::{derive_message_formats, violation};
|
||||
use ruff_python_ast::call_path::compose_call_path;
|
||||
use ruff_python_ast::helpers;
|
||||
use ruff_python_ast::{self as ast, Constant, ExceptHandler, Expr, Stmt};
|
||||
use ruff_python_ast::{self as ast, ExceptHandler, Stmt};
|
||||
use ruff_text_size::Ranged;
|
||||
use ruff_text_size::{TextLen, TextRange};
|
||||
|
||||
|
@ -64,13 +64,7 @@ impl Violation for SuppressibleException {
|
|||
fn is_empty(body: &[Stmt]) -> bool {
|
||||
match body {
|
||||
[Stmt::Pass(_)] => true,
|
||||
[Stmt::Expr(ast::StmtExpr { value, range: _ })] => matches!(
|
||||
value.as_ref(),
|
||||
Expr::Constant(ast::ExprConstant {
|
||||
value: Constant::Ellipsis,
|
||||
..
|
||||
})
|
||||
),
|
||||
[Stmt::Expr(ast::StmtExpr { value, range: _ })] => value.is_ellipsis_literal_expr(),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -82,15 +82,14 @@ impl Violation for YodaConditions {
|
|||
fn is_constant_like(expr: &Expr) -> bool {
|
||||
match expr {
|
||||
Expr::Attribute(ast::ExprAttribute { attr, .. }) => str::is_cased_uppercase(attr),
|
||||
Expr::Constant(_) => true,
|
||||
Expr::Tuple(ast::ExprTuple { elts, .. }) => elts.iter().all(is_constant_like),
|
||||
Expr::Name(ast::ExprName { id, .. }) => str::is_cased_uppercase(id),
|
||||
Expr::UnaryOp(ast::ExprUnaryOp {
|
||||
op: UnaryOp::UAdd | UnaryOp::USub | UnaryOp::Invert,
|
||||
operand,
|
||||
range: _,
|
||||
}) => operand.is_constant_expr(),
|
||||
_ => false,
|
||||
}) => operand.is_literal_expr(),
|
||||
_ => expr.is_literal_expr(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use ruff_python_ast::{self as ast, Constant, Expr, Stmt};
|
||||
use ruff_python_ast::{self as ast, Expr, Stmt};
|
||||
|
||||
use ruff_python_ast::helpers::is_docstring_stmt;
|
||||
|
||||
|
@ -7,15 +7,7 @@ use ruff_python_ast::helpers::is_docstring_stmt;
|
|||
fn is_empty_stmt(stmt: &Stmt) -> bool {
|
||||
match stmt {
|
||||
Stmt::Pass(_) => return true,
|
||||
Stmt::Expr(ast::StmtExpr { value, range: _ }) => {
|
||||
return matches!(
|
||||
value.as_ref(),
|
||||
Expr::Constant(ast::ExprConstant {
|
||||
value: Constant::Ellipsis,
|
||||
..
|
||||
})
|
||||
)
|
||||
}
|
||||
Stmt::Expr(ast::StmtExpr { value, range: _ }) => return value.is_ellipsis_literal_expr(),
|
||||
Stmt::Raise(ast::StmtRaise { exc, cause, .. }) => {
|
||||
if cause.is_none() {
|
||||
if let Some(exc) = exc {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use ruff_python_ast::{self as ast, Arguments, Constant, Expr, ExprCall, ExprConstant};
|
||||
use ruff_python_ast::{self as ast, Arguments, Expr, ExprCall};
|
||||
|
||||
use ruff_diagnostics::{AlwaysFixableViolation, Diagnostic, Edit, Fix};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
|
@ -65,11 +65,7 @@ pub(crate) fn path_constructor_current_directory(checker: &mut Checker, expr: &E
|
|||
return;
|
||||
}
|
||||
|
||||
let [Expr::Constant(ExprConstant {
|
||||
value: Constant::Str(ast::StringConstant { value, .. }),
|
||||
range,
|
||||
})] = args.as_slice()
|
||||
else {
|
||||
let [Expr::StringLiteral(ast::ExprStringLiteral { value, range, .. })] = args.as_slice() else {
|
||||
return;
|
||||
};
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use ruff_diagnostics::{Diagnostic, DiagnosticKind};
|
||||
use ruff_python_ast::{Constant, Expr, ExprCall, ExprConstant};
|
||||
use ruff_python_ast::{Expr, ExprBooleanLiteral, ExprCall};
|
||||
use ruff_text_size::Ranged;
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
|
@ -118,24 +118,13 @@ pub(crate) fn replaceable_by_pathlib(checker: &mut Checker, call: &ExprCall) {
|
|||
.is_some_and(|expr| {
|
||||
!matches!(
|
||||
expr,
|
||||
Expr::Constant(ExprConstant {
|
||||
value: Constant::Bool(true),
|
||||
..
|
||||
})
|
||||
Expr::BooleanLiteral(ExprBooleanLiteral { value: true, .. })
|
||||
)
|
||||
})
|
||||
|| call
|
||||
.arguments
|
||||
.find_argument("opener", 7)
|
||||
.is_some_and(|expr| {
|
||||
!matches!(
|
||||
expr,
|
||||
Expr::Constant(ExprConstant {
|
||||
value: Constant::None,
|
||||
..
|
||||
})
|
||||
)
|
||||
})
|
||||
.is_some_and(|expr| !expr.is_none_literal_expr())
|
||||
{
|
||||
return None;
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use ruff_python_ast::{self as ast, Arguments, Constant, ConversionFlag, Expr};
|
||||
use ruff_python_ast::{self as ast, Arguments, ConversionFlag, Expr};
|
||||
use ruff_text_size::TextRange;
|
||||
|
||||
/// Wrap an expression in a `FormattedValue` with no special formatting.
|
||||
|
@ -15,8 +15,10 @@ fn to_formatted_value_expr(inner: &Expr) -> Expr {
|
|||
|
||||
/// Convert a string to a constant string expression.
|
||||
pub(super) fn to_constant_string(s: &str) -> Expr {
|
||||
let node = ast::ExprConstant {
|
||||
value: s.to_owned().into(),
|
||||
let node = ast::ExprStringLiteral {
|
||||
value: s.to_owned(),
|
||||
unicode: false,
|
||||
implicit_concatenated: false,
|
||||
range: TextRange::default(),
|
||||
};
|
||||
node.into()
|
||||
|
@ -54,20 +56,11 @@ fn is_simple_callee(func: &Expr) -> bool {
|
|||
pub(super) fn to_f_string_element(expr: &Expr) -> Option<Expr> {
|
||||
match expr {
|
||||
// These are directly handled by `unparse_f_string_element`:
|
||||
Expr::Constant(ast::ExprConstant {
|
||||
value: Constant::Str(_),
|
||||
..
|
||||
})
|
||||
| Expr::FString(_)
|
||||
| Expr::FormattedValue(_) => Some(expr.clone()),
|
||||
Expr::StringLiteral(_) | Expr::FString(_) | Expr::FormattedValue(_) => Some(expr.clone()),
|
||||
// These should be pretty safe to wrap in a formatted value.
|
||||
Expr::Constant(ast::ExprConstant {
|
||||
value:
|
||||
Constant::Int(_) | Constant::Float(_) | Constant::Bool(_) | Constant::Complex { .. },
|
||||
..
|
||||
})
|
||||
| Expr::Name(_)
|
||||
| Expr::Attribute(_) => Some(to_formatted_value_expr(expr)),
|
||||
Expr::NumberLiteral(_) | Expr::BooleanLiteral(_) | Expr::Name(_) | Expr::Attribute(_) => {
|
||||
Some(to_formatted_value_expr(expr))
|
||||
}
|
||||
Expr::Call(_) if is_simple_call(expr) => Some(to_formatted_value_expr(expr)),
|
||||
_ => None,
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@ use itertools::Itertools;
|
|||
use crate::fix::edits::pad;
|
||||
use ruff_diagnostics::{AlwaysFixableViolation, Diagnostic, Edit, Fix};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
use ruff_python_ast::{self as ast, Arguments, Constant, Expr};
|
||||
use ruff_python_ast::{self as ast, Arguments, Expr};
|
||||
use ruff_text_size::{Ranged, TextRange};
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
|
@ -61,31 +61,20 @@ fn is_static_length(elts: &[Expr]) -> bool {
|
|||
|
||||
fn build_fstring(joiner: &str, joinees: &[Expr]) -> Option<Expr> {
|
||||
// If all elements are string constants, join them into a single string.
|
||||
if joinees.iter().all(|expr| {
|
||||
matches!(
|
||||
expr,
|
||||
Expr::Constant(ast::ExprConstant {
|
||||
value: Constant::Str(_),
|
||||
..
|
||||
})
|
||||
)
|
||||
}) {
|
||||
let node = ast::ExprConstant {
|
||||
if joinees.iter().all(Expr::is_string_literal_expr) {
|
||||
let node = ast::ExprStringLiteral {
|
||||
value: joinees
|
||||
.iter()
|
||||
.filter_map(|expr| {
|
||||
if let Expr::Constant(ast::ExprConstant {
|
||||
value: Constant::Str(ast::StringConstant { value, .. }),
|
||||
..
|
||||
}) = expr
|
||||
{
|
||||
if let Expr::StringLiteral(ast::ExprStringLiteral { value, .. }) = expr {
|
||||
Some(value.as_str())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.join(joiner)
|
||||
.into(),
|
||||
.join(joiner),
|
||||
unicode: false,
|
||||
implicit_concatenated: false,
|
||||
range: TextRange::default(),
|
||||
};
|
||||
return Some(node.into());
|
||||
|
|
|
@ -16,7 +16,12 @@ pub(super) enum Resolution {
|
|||
/// Test an [`Expr`] for relevance to Pandas-related operations.
|
||||
pub(super) fn test_expression(expr: &Expr, semantic: &SemanticModel) -> Resolution {
|
||||
match expr {
|
||||
Expr::Constant(_)
|
||||
Expr::StringLiteral(_)
|
||||
| Expr::BytesLiteral(_)
|
||||
| Expr::NumberLiteral(_)
|
||||
| Expr::BooleanLiteral(_)
|
||||
| Expr::NoneLiteral(_)
|
||||
| Expr::EllipsisLiteral(_)
|
||||
| Expr::Tuple(_)
|
||||
| Expr::List(_)
|
||||
| Expr::Set(_)
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use ruff_diagnostics::Diagnostic;
|
||||
use ruff_diagnostics::Violation;
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
use ruff_python_ast::{self as ast, CmpOp, Constant, Expr, Int};
|
||||
use ruff_python_ast::{self as ast, CmpOp, Expr, Int};
|
||||
use ruff_text_size::Ranged;
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
|
@ -80,8 +80,8 @@ pub(crate) fn nunique_constant_series_check(
|
|||
// Right should be the integer 1.
|
||||
if !matches!(
|
||||
right,
|
||||
Expr::Constant(ast::ExprConstant {
|
||||
value: Constant::Int(Int::ONE),
|
||||
Expr::NumberLiteral(ast::ExprNumberLiteral {
|
||||
value: ast::Number::Int(Int::ONE),
|
||||
range: _,
|
||||
})
|
||||
) {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
use ruff_python_ast as ast;
|
||||
use ruff_python_ast::{Constant, Expr};
|
||||
use ruff_python_ast::Expr;
|
||||
use ruff_text_size::Ranged;
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
|
@ -51,10 +51,7 @@ pub(crate) fn use_of_read_table(checker: &mut Checker, call: &ast::ExprCall) {
|
|||
.resolve_call_path(&call.func)
|
||||
.is_some_and(|call_path| matches!(call_path.as_slice(), ["pandas", "read_table"]))
|
||||
{
|
||||
if let Some(Expr::Constant(ast::ExprConstant {
|
||||
value: Constant::Str(ast::StringConstant { value, .. }),
|
||||
..
|
||||
})) = call
|
||||
if let Some(Expr::StringLiteral(ast::ExprStringLiteral { value, .. })) = call
|
||||
.arguments
|
||||
.find_keyword("sep")
|
||||
.map(|keyword| &keyword.value)
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use ruff_python_ast::{
|
||||
self as ast, Constant, Expr, Identifier, Parameter, ParameterWithDefault, Parameters, Stmt,
|
||||
self as ast, Expr, Identifier, Parameter, ParameterWithDefault, Parameters, Stmt,
|
||||
};
|
||||
use ruff_text_size::{Ranged, TextRange};
|
||||
|
||||
|
@ -164,10 +164,7 @@ fn extract_types(annotation: &Expr, semantic: &SemanticModel) -> Option<(Vec<Exp
|
|||
// specification, or ellipsis.
|
||||
let params = match param_types {
|
||||
Expr::List(ast::ExprList { elts, .. }) => elts.clone(),
|
||||
Expr::Constant(ast::ExprConstant {
|
||||
value: Constant::Ellipsis,
|
||||
..
|
||||
}) => vec![],
|
||||
Expr::EllipsisLiteral(_) => vec![],
|
||||
_ => return None,
|
||||
};
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@ use ruff_diagnostics::{AlwaysFixableViolation, Diagnostic, Edit, Fix};
|
|||
use ruff_macros::{derive_message_formats, violation};
|
||||
use ruff_python_ast::helpers;
|
||||
use ruff_python_ast::helpers::{generate_comparison, is_const_none};
|
||||
use ruff_python_ast::{self as ast, CmpOp, Constant, Expr};
|
||||
use ruff_python_ast::{self as ast, CmpOp, Expr};
|
||||
use ruff_text_size::Ranged;
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
|
@ -164,11 +164,7 @@ pub(crate) fn literal_comparisons(checker: &mut Checker, compare: &ast::ExprComp
|
|||
}
|
||||
|
||||
if checker.enabled(Rule::TrueFalseComparison) {
|
||||
if let Expr::Constant(ast::ExprConstant {
|
||||
value: Constant::Bool(value),
|
||||
range: _,
|
||||
}) = comparator
|
||||
{
|
||||
if let Expr::BooleanLiteral(ast::ExprBooleanLiteral { value, .. }) = comparator {
|
||||
match op {
|
||||
EqCmpOp::Eq => {
|
||||
let diagnostic = Diagnostic::new(
|
||||
|
@ -224,11 +220,7 @@ pub(crate) fn literal_comparisons(checker: &mut Checker, compare: &ast::ExprComp
|
|||
}
|
||||
|
||||
if checker.enabled(Rule::TrueFalseComparison) {
|
||||
if let Expr::Constant(ast::ExprConstant {
|
||||
value: Constant::Bool(value),
|
||||
range: _,
|
||||
}) = next
|
||||
{
|
||||
if let Expr::BooleanLiteral(ast::ExprBooleanLiteral { value, .. }) = next {
|
||||
match op {
|
||||
EqCmpOp::Eq => {
|
||||
let diagnostic =
|
||||
|
|
|
@ -2,7 +2,6 @@ use std::collections::BTreeSet;
|
|||
|
||||
use ruff_python_ast::call_path::from_qualified_name;
|
||||
use ruff_python_ast::helpers::map_callable;
|
||||
use ruff_python_ast::Expr;
|
||||
use ruff_python_semantic::{Definition, SemanticModel};
|
||||
use ruff_source_file::UniversalNewlines;
|
||||
|
||||
|
@ -61,13 +60,3 @@ pub(crate) fn should_ignore_definition(
|
|||
})
|
||||
})
|
||||
}
|
||||
|
||||
/// Check if a docstring should be ignored.
|
||||
pub(crate) fn should_ignore_docstring(docstring: &Expr) -> bool {
|
||||
// Avoid analyzing docstrings that contain implicit string concatenations.
|
||||
// Python does consider these docstrings, but they're almost certainly a
|
||||
// user error, and supporting them "properly" is extremely difficult.
|
||||
docstring
|
||||
.as_constant_expr()
|
||||
.is_some_and(|constant| constant.value.is_implicit_concatenated())
|
||||
}
|
||||
|
|
|
@ -86,7 +86,7 @@ pub(crate) fn capitalized(checker: &mut Checker, docstring: &Docstring) {
|
|||
first_word: first_word.to_string(),
|
||||
capitalized_word: capitalized_word.to_string(),
|
||||
},
|
||||
docstring.expr.range(),
|
||||
docstring.range(),
|
||||
);
|
||||
|
||||
diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement(
|
||||
|
|
|
@ -96,8 +96,8 @@ pub(crate) fn newline_after_last_paragraph(checker: &mut Checker, docstring: &Do
|
|||
);
|
||||
diagnostic.set_fix(Fix::safe_edit(Edit::replacement(
|
||||
content,
|
||||
docstring.expr.end() - num_trailing_quotes - num_trailing_spaces,
|
||||
docstring.expr.end() - num_trailing_quotes,
|
||||
docstring.end() - num_trailing_quotes - num_trailing_spaces,
|
||||
docstring.end() - num_trailing_quotes,
|
||||
)));
|
||||
checker.diagnostics.push(diagnostic);
|
||||
}
|
||||
|
|
|
@ -149,7 +149,14 @@ pub(crate) fn repeated_keys(checker: &mut Checker, dict: &ast::ExprDict) {
|
|||
};
|
||||
|
||||
match key {
|
||||
Expr::Constant(_) | Expr::Tuple(_) | Expr::FString(_) => {
|
||||
Expr::StringLiteral(_)
|
||||
| Expr::BytesLiteral(_)
|
||||
| Expr::NumberLiteral(_)
|
||||
| Expr::BooleanLiteral(_)
|
||||
| Expr::NoneLiteral(_)
|
||||
| Expr::EllipsisLiteral(_)
|
||||
| Expr::Tuple(_)
|
||||
| Expr::FString(_) => {
|
||||
if checker.enabled(Rule::MultiValueRepeatedKeyLiteral) {
|
||||
let mut diagnostic = Diagnostic::new(
|
||||
MultiValueRepeatedKeyLiteral {
|
||||
|
|
|
@ -4,7 +4,7 @@ use rustc_hash::FxHashSet;
|
|||
|
||||
use ruff_diagnostics::{AlwaysFixableViolation, Diagnostic, Fix, FixAvailability, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
use ruff_python_ast::{self as ast, Constant, Expr, Identifier, Keyword};
|
||||
use ruff_python_ast::{self as ast, Expr, Identifier, Keyword};
|
||||
use ruff_text_size::{Ranged, TextRange};
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
|
@ -582,10 +582,7 @@ pub(crate) fn percent_format_extra_named_arguments(
|
|||
.iter()
|
||||
.enumerate()
|
||||
.filter_map(|(index, key)| match key {
|
||||
Some(Expr::Constant(ast::ExprConstant {
|
||||
value: Constant::Str(ast::StringConstant { value, .. }),
|
||||
..
|
||||
})) => {
|
||||
Some(Expr::StringLiteral(ast::ExprStringLiteral { value, .. })) => {
|
||||
if summary.keywords.contains(value.as_str()) {
|
||||
None
|
||||
} else {
|
||||
|
@ -643,10 +640,7 @@ pub(crate) fn percent_format_missing_arguments(
|
|||
let mut keywords = FxHashSet::default();
|
||||
for key in keys.iter().flatten() {
|
||||
match key {
|
||||
Expr::Constant(ast::ExprConstant {
|
||||
value: Constant::Str(ast::StringConstant { value, .. }),
|
||||
..
|
||||
}) => {
|
||||
Expr::StringLiteral(ast::ExprStringLiteral { value, .. }) => {
|
||||
keywords.insert(value);
|
||||
}
|
||||
_ => {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use std::fmt;
|
||||
|
||||
use ruff_python_ast as ast;
|
||||
use ruff_python_ast::{Arguments, CmpOp, Constant, Expr};
|
||||
use ruff_python_ast::{Arguments, CmpOp, Expr};
|
||||
use ruff_python_semantic::analyze::function_type;
|
||||
use ruff_python_semantic::{ScopeKind, SemanticModel};
|
||||
|
||||
|
@ -11,11 +11,7 @@ use crate::settings::LinterSettings;
|
|||
pub(super) fn type_param_name(arguments: &Arguments) -> Option<&str> {
|
||||
// Handle both `TypeVar("T")` and `TypeVar(name="T")`.
|
||||
let name_param = arguments.find_argument("name", 0)?;
|
||||
if let Expr::Constant(ast::ExprConstant {
|
||||
value: Constant::Str(name),
|
||||
..
|
||||
}) = &name_param
|
||||
{
|
||||
if let Expr::StringLiteral(ast::ExprStringLiteral { value: name, .. }) = &name_param {
|
||||
Some(name)
|
||||
} else {
|
||||
None
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use ruff_python_ast::{self as ast, Constant, Expr};
|
||||
use ruff_python_ast::{self as ast, Expr};
|
||||
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
|
@ -45,51 +45,48 @@ impl Violation for AssertOnStringLiteral {
|
|||
/// PLW0129
|
||||
pub(crate) fn assert_on_string_literal(checker: &mut Checker, test: &Expr) {
|
||||
match test {
|
||||
Expr::Constant(ast::ExprConstant { value, .. }) => match value {
|
||||
Constant::Str(value, ..) => {
|
||||
checker.diagnostics.push(Diagnostic::new(
|
||||
AssertOnStringLiteral {
|
||||
kind: if value.is_empty() {
|
||||
Kind::Empty
|
||||
} else {
|
||||
Kind::NonEmpty
|
||||
},
|
||||
Expr::StringLiteral(ast::ExprStringLiteral { value, .. }) => {
|
||||
checker.diagnostics.push(Diagnostic::new(
|
||||
AssertOnStringLiteral {
|
||||
kind: if value.is_empty() {
|
||||
Kind::Empty
|
||||
} else {
|
||||
Kind::NonEmpty
|
||||
},
|
||||
test.range(),
|
||||
));
|
||||
}
|
||||
Constant::Bytes(value) => {
|
||||
checker.diagnostics.push(Diagnostic::new(
|
||||
AssertOnStringLiteral {
|
||||
kind: if value.is_empty() {
|
||||
Kind::Empty
|
||||
} else {
|
||||
Kind::NonEmpty
|
||||
},
|
||||
},
|
||||
test.range(),
|
||||
));
|
||||
}
|
||||
Expr::BytesLiteral(ast::ExprBytesLiteral { value, .. }) => {
|
||||
checker.diagnostics.push(Diagnostic::new(
|
||||
AssertOnStringLiteral {
|
||||
kind: if value.is_empty() {
|
||||
Kind::Empty
|
||||
} else {
|
||||
Kind::NonEmpty
|
||||
},
|
||||
test.range(),
|
||||
));
|
||||
}
|
||||
_ => {}
|
||||
},
|
||||
},
|
||||
test.range(),
|
||||
));
|
||||
}
|
||||
Expr::FString(ast::ExprFString { values, .. }) => {
|
||||
checker.diagnostics.push(Diagnostic::new(
|
||||
AssertOnStringLiteral {
|
||||
kind: if values.iter().all(|value| match value {
|
||||
Expr::Constant(ast::ExprConstant { value, .. }) => match value {
|
||||
Constant::Str(value) => value.is_empty(),
|
||||
Constant::Bytes(value) => value.is_empty(),
|
||||
_ => false,
|
||||
},
|
||||
Expr::StringLiteral(ast::ExprStringLiteral { value, .. }) => {
|
||||
value.is_empty()
|
||||
}
|
||||
Expr::BytesLiteral(ast::ExprBytesLiteral { value, .. }) => value.is_empty(),
|
||||
_ => false,
|
||||
}) {
|
||||
Kind::Empty
|
||||
} else if values.iter().any(|value| match value {
|
||||
Expr::Constant(ast::ExprConstant { value, .. }) => match value {
|
||||
Constant::Str(value) => !value.is_empty(),
|
||||
Constant::Bytes(value) => !value.is_empty(),
|
||||
_ => false,
|
||||
},
|
||||
Expr::StringLiteral(ast::ExprStringLiteral { value, .. }) => {
|
||||
!value.is_empty()
|
||||
}
|
||||
Expr::BytesLiteral(ast::ExprBytesLiteral { value, .. }) => {
|
||||
!value.is_empty()
|
||||
}
|
||||
_ => false,
|
||||
}) {
|
||||
Kind::NonEmpty
|
||||
|
|
|
@ -2,7 +2,7 @@ use bitflags::bitflags;
|
|||
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
use ruff_python_ast::{self as ast, Constant, Expr};
|
||||
use ruff_python_ast::{self as ast, Expr};
|
||||
use ruff_python_semantic::SemanticModel;
|
||||
use ruff_text_size::Ranged;
|
||||
|
||||
|
@ -59,11 +59,7 @@ pub(crate) fn bad_open_mode(checker: &mut Checker, call: &ast::ExprCall) {
|
|||
return;
|
||||
};
|
||||
|
||||
let Expr::Constant(ast::ExprConstant {
|
||||
value: Constant::Str(ast::StringConstant { value, .. }),
|
||||
..
|
||||
}) = mode
|
||||
else {
|
||||
let Some(ast::ExprStringLiteral { value, .. }) = mode.as_string_literal_expr() else {
|
||||
return;
|
||||
};
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use std::fmt;
|
||||
|
||||
use ruff_python_ast::{self as ast, Constant, Expr};
|
||||
use ruff_python_ast::{self as ast, Expr};
|
||||
use rustc_hash::FxHashSet;
|
||||
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
|
@ -146,18 +146,11 @@ pub(crate) fn bad_str_strip_call(checker: &mut Checker, func: &Expr, args: &[Exp
|
|||
if let Expr::Attribute(ast::ExprAttribute { value, attr, .. }) = func {
|
||||
if matches!(
|
||||
value.as_ref(),
|
||||
Expr::Constant(ast::ExprConstant {
|
||||
value: Constant::Str(_) | Constant::Bytes(_),
|
||||
..
|
||||
})
|
||||
Expr::StringLiteral(_) | Expr::BytesLiteral(_)
|
||||
) {
|
||||
if let Some(strip) = StripKind::from_str(attr.as_str()) {
|
||||
if let Some(arg) = args.get(0) {
|
||||
if let Expr::Constant(ast::ExprConstant {
|
||||
value: Constant::Str(value),
|
||||
..
|
||||
}) = &arg
|
||||
{
|
||||
if let Expr::StringLiteral(ast::ExprStringLiteral { value, .. }) = &arg {
|
||||
if has_duplicates(value) {
|
||||
let removal = if checker.settings.target_version >= PythonVersion::Py39
|
||||
{
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use std::str::FromStr;
|
||||
|
||||
use ruff_python_ast::{self as ast, Constant, Expr};
|
||||
use ruff_python_ast::{self as ast, Expr};
|
||||
use ruff_python_literal::cformat::{CFormatPart, CFormatSpec, CFormatStrOrBytes, CFormatString};
|
||||
use ruff_python_parser::{lexer, AsMode};
|
||||
use ruff_text_size::{Ranged, TextRange};
|
||||
|
@ -186,12 +186,8 @@ fn is_valid_dict(
|
|||
let Some(key) = key else {
|
||||
return true;
|
||||
};
|
||||
if let Expr::Constant(ast::ExprConstant {
|
||||
value:
|
||||
Constant::Str(ast::StringConstant {
|
||||
value: mapping_key, ..
|
||||
}),
|
||||
..
|
||||
if let Expr::StringLiteral(ast::ExprStringLiteral {
|
||||
value: mapping_key, ..
|
||||
}) = key
|
||||
{
|
||||
let Some(format) = formats_hash.get(mapping_key.as_str()) else {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use anyhow::bail;
|
||||
use itertools::Itertools;
|
||||
use ruff_python_ast::{self as ast, CmpOp, Constant, Expr};
|
||||
use ruff_python_ast::{self as ast, CmpOp, Expr};
|
||||
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
|
@ -83,43 +83,39 @@ pub(crate) fn compare_to_empty_string(
|
|||
if let Ok(op) = EmptyStringCmpOp::try_from(op) {
|
||||
if std::mem::take(&mut first) {
|
||||
// Check the left-most expression.
|
||||
if let Expr::Constant(ast::ExprConstant { value, .. }) = &lhs {
|
||||
if let Constant::Str(s) = value {
|
||||
if s.is_empty() {
|
||||
let constant = checker.generator().constant(value);
|
||||
let expr = checker.generator().expr(rhs);
|
||||
let existing = format!("{constant} {op} {expr}");
|
||||
let replacement = format!("{}{expr}", op.into_unary());
|
||||
checker.diagnostics.push(Diagnostic::new(
|
||||
CompareToEmptyString {
|
||||
existing,
|
||||
replacement,
|
||||
},
|
||||
lhs.range(),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check all right-hand expressions.
|
||||
if let Expr::Constant(ast::ExprConstant { value, .. }) = &rhs {
|
||||
if let Constant::Str(s) = value {
|
||||
if s.is_empty() {
|
||||
let expr = checker.generator().expr(lhs);
|
||||
let constant = checker.generator().constant(value);
|
||||
let existing = format!("{expr} {op} {constant}");
|
||||
if let Expr::StringLiteral(ast::ExprStringLiteral { value, .. }) = &lhs {
|
||||
if value.is_empty() {
|
||||
let literal = checker.generator().expr(lhs);
|
||||
let expr = checker.generator().expr(rhs);
|
||||
let existing = format!("{literal} {op} {expr}");
|
||||
let replacement = format!("{}{expr}", op.into_unary());
|
||||
checker.diagnostics.push(Diagnostic::new(
|
||||
CompareToEmptyString {
|
||||
existing,
|
||||
replacement,
|
||||
},
|
||||
rhs.range(),
|
||||
lhs.range(),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check all right-hand expressions.
|
||||
if let Expr::StringLiteral(ast::ExprStringLiteral { value, .. }) = &rhs {
|
||||
if value.is_empty() {
|
||||
let expr = checker.generator().expr(lhs);
|
||||
let literal = checker.generator().expr(rhs);
|
||||
let existing = format!("{expr} {op} {literal}");
|
||||
let replacement = format!("{}{expr}", op.into_unary());
|
||||
checker.diagnostics.push(Diagnostic::new(
|
||||
CompareToEmptyString {
|
||||
existing,
|
||||
replacement,
|
||||
},
|
||||
rhs.range(),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use itertools::Itertools;
|
||||
use ruff_python_ast::{self as ast, CmpOp, Expr};
|
||||
use ruff_python_ast::{CmpOp, Expr};
|
||||
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
|
@ -63,22 +63,12 @@ pub(crate) fn comparison_of_constant(
|
|||
.tuple_windows()
|
||||
.zip(ops)
|
||||
{
|
||||
if let (
|
||||
Expr::Constant(ast::ExprConstant {
|
||||
value: left_constant,
|
||||
..
|
||||
}),
|
||||
Expr::Constant(ast::ExprConstant {
|
||||
value: right_constant,
|
||||
..
|
||||
}),
|
||||
) = (&left, &right)
|
||||
{
|
||||
if left.is_literal_expr() && right.is_literal_expr() {
|
||||
let diagnostic = Diagnostic::new(
|
||||
ComparisonOfConstant {
|
||||
left_constant: checker.generator().constant(left_constant),
|
||||
left_constant: checker.generator().expr(left),
|
||||
op: *op,
|
||||
right_constant: checker.generator().constant(right_constant),
|
||||
right_constant: checker.generator().expr(right),
|
||||
},
|
||||
left.range(),
|
||||
);
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
use ruff_python_ast::{self as ast, Constant, Expr, Operator};
|
||||
use ruff_python_ast::{self as ast, Expr, Operator};
|
||||
use ruff_text_size::Ranged;
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
|
@ -73,10 +73,7 @@ fn is_valid_default(expr: &Expr) -> bool {
|
|||
// Otherwise, the default must be a string or `None`.
|
||||
matches!(
|
||||
expr,
|
||||
Expr::Constant(ast::ExprConstant {
|
||||
value: Constant::Str { .. } | Constant::None { .. },
|
||||
..
|
||||
}) | Expr::FString(_)
|
||||
Expr::StringLiteral(_) | Expr::NoneLiteral(_) | Expr::FString(_)
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
use ruff_python_ast::{self as ast};
|
||||
use ruff_python_ast as ast;
|
||||
use ruff_python_semantic::analyze::type_inference::{PythonType, ResolvedPythonType};
|
||||
use ruff_text_size::Ranged;
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
use ruff_python_ast::{self as ast, Constant, Expr};
|
||||
use ruff_python_ast::{self as ast, Expr};
|
||||
use ruff_python_semantic::analyze::logging;
|
||||
use ruff_python_stdlib::logging::LoggingLevel;
|
||||
use ruff_text_size::Ranged;
|
||||
|
@ -128,10 +128,8 @@ pub(crate) fn logging_call(checker: &mut Checker, call: &ast::ExprCall) {
|
|||
_ => return,
|
||||
};
|
||||
|
||||
let Some(Expr::Constant(ast::ExprConstant {
|
||||
value: Constant::Str(ast::StringConstant { value, .. }),
|
||||
..
|
||||
})) = call.arguments.find_positional(0)
|
||||
let Some(Expr::StringLiteral(ast::ExprStringLiteral { value, .. })) =
|
||||
call.arguments.find_positional(0)
|
||||
else {
|
||||
return;
|
||||
};
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use itertools::Itertools;
|
||||
use ruff_python_ast::{self as ast, Constant, Expr, Int, UnaryOp};
|
||||
use ruff_python_ast::{self as ast, Expr, Int, UnaryOp};
|
||||
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
|
@ -57,42 +57,39 @@ impl Violation for MagicValueComparison {
|
|||
}
|
||||
}
|
||||
|
||||
/// If an [`Expr`] is a constant (or unary operation on a constant), return the [`Constant`].
|
||||
fn as_constant(expr: &Expr) -> Option<&Constant> {
|
||||
/// If an [`Expr`] is a literal (or unary operation on a literal), return the literal [`Expr`].
|
||||
fn as_literal(expr: &Expr) -> Option<&Expr> {
|
||||
match expr {
|
||||
Expr::Constant(ast::ExprConstant { value, .. }) => Some(value),
|
||||
Expr::UnaryOp(ast::ExprUnaryOp {
|
||||
op: UnaryOp::UAdd | UnaryOp::USub | UnaryOp::Invert,
|
||||
operand,
|
||||
range: _,
|
||||
}) => match operand.as_ref() {
|
||||
Expr::Constant(ast::ExprConstant { value, .. }) => Some(value),
|
||||
_ => None,
|
||||
},
|
||||
..
|
||||
}) if operand.is_literal_expr() => Some(operand.as_ref()),
|
||||
expr if expr.is_literal_expr() => Some(expr),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Return `true` if a [`Constant`] is a magic value.
|
||||
fn is_magic_value(constant: &Constant, allowed_types: &[ConstantType]) -> bool {
|
||||
if let Ok(constant_type) = ConstantType::try_from(constant) {
|
||||
fn is_magic_value(expr: &Expr, allowed_types: &[ConstantType]) -> bool {
|
||||
if let Some(constant_type) = ConstantType::try_from_expr(expr) {
|
||||
if allowed_types.contains(&constant_type) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
match constant {
|
||||
|
||||
match expr {
|
||||
// Ignore `None`, `Bool`, and `Ellipsis` constants.
|
||||
Constant::None => false,
|
||||
Constant::Bool(_) => false,
|
||||
Constant::Ellipsis => false,
|
||||
// Otherwise, special-case some common string and integer types.
|
||||
Constant::Str(ast::StringConstant { value, .. }) => {
|
||||
Expr::NoneLiteral(_) | Expr::BooleanLiteral(_) | Expr::EllipsisLiteral(_) => false,
|
||||
// Special-case some common string and integer types.
|
||||
Expr::StringLiteral(ast::ExprStringLiteral { value, .. }) => {
|
||||
!matches!(value.as_str(), "" | "__main__")
|
||||
}
|
||||
Constant::Int(value) => !matches!(*value, Int::ZERO | Int::ONE),
|
||||
Constant::Bytes(_) => true,
|
||||
Constant::Float(_) => true,
|
||||
Constant::Complex { .. } => true,
|
||||
Expr::NumberLiteral(ast::ExprNumberLiteral { value, .. }) => match value {
|
||||
ast::Number::Int(value) => !matches!(*value, Int::ZERO | Int::ONE),
|
||||
_ => true,
|
||||
},
|
||||
Expr::BytesLiteral(_) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -102,15 +99,15 @@ pub(crate) fn magic_value_comparison(checker: &mut Checker, left: &Expr, compara
|
|||
.chain(comparators.iter())
|
||||
.tuple_windows()
|
||||
{
|
||||
// If both of the comparators are constant, skip rule for the whole expression.
|
||||
// If both of the comparators are literals, skip rule for the whole expression.
|
||||
// R0133: comparison-of-constants
|
||||
if as_constant(left).is_some() && as_constant(right).is_some() {
|
||||
if as_literal(left).is_some() && as_literal(right).is_some() {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
for comparison_expr in std::iter::once(left).chain(comparators.iter()) {
|
||||
if let Some(value) = as_constant(comparison_expr) {
|
||||
if let Some(value) = as_literal(comparison_expr) {
|
||||
if is_magic_value(value, &checker.settings.pylint.allow_magic_value_types) {
|
||||
checker.diagnostics.push(Diagnostic::new(
|
||||
MagicValueComparison {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use ruff_python_ast::{self as ast, Constant, Expr, Stmt, StmtClassDef};
|
||||
use ruff_python_ast::{self as ast, Expr, Stmt, StmtClassDef};
|
||||
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
|
@ -65,13 +65,7 @@ pub(crate) fn single_string_slots(checker: &mut Checker, class: &StmtClassDef) {
|
|||
for target in targets {
|
||||
if let Expr::Name(ast::ExprName { id, .. }) = target {
|
||||
if id.as_str() == "__slots__" {
|
||||
if matches!(
|
||||
value.as_ref(),
|
||||
Expr::Constant(ast::ExprConstant {
|
||||
value: Constant::Str(_),
|
||||
..
|
||||
}) | Expr::FString(_)
|
||||
) {
|
||||
if matches!(value.as_ref(), Expr::StringLiteral(_) | Expr::FString(_)) {
|
||||
checker
|
||||
.diagnostics
|
||||
.push(Diagnostic::new(SingleStringSlots, stmt.identifier()));
|
||||
|
@ -87,13 +81,7 @@ pub(crate) fn single_string_slots(checker: &mut Checker, class: &StmtClassDef) {
|
|||
}) => {
|
||||
if let Expr::Name(ast::ExprName { id, .. }) = target.as_ref() {
|
||||
if id.as_str() == "__slots__" {
|
||||
if matches!(
|
||||
value.as_ref(),
|
||||
Expr::Constant(ast::ExprConstant {
|
||||
value: Constant::Str(_),
|
||||
..
|
||||
}) | Expr::FString(_)
|
||||
) {
|
||||
if matches!(value.as_ref(), Expr::StringLiteral(_) | Expr::FString(_)) {
|
||||
checker
|
||||
.diagnostics
|
||||
.push(Diagnostic::new(SingleStringSlots, stmt.identifier()));
|
||||
|
|
|
@ -81,7 +81,7 @@ pub(crate) fn unspecified_encoding(checker: &mut Checker, call: &ast::ExprCall)
|
|||
|
||||
/// Returns `true` if the given expression is a string literal containing a `b` character.
|
||||
fn is_binary_mode(expr: &ast::Expr) -> Option<bool> {
|
||||
Some(expr.as_constant_expr()?.value.as_str()?.value.contains('b'))
|
||||
Some(expr.as_string_literal_expr()?.value.contains('b'))
|
||||
}
|
||||
|
||||
/// Returns `true` if the given call lacks an explicit `encoding`.
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use ruff_python_ast::{self as ast, Constant, Expr, Stmt};
|
||||
use ruff_python_ast::{self as ast, Expr, Stmt};
|
||||
|
||||
use ruff_diagnostics::{AlwaysFixableViolation, Diagnostic, Fix};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
|
@ -72,13 +72,7 @@ pub(crate) fn useless_return(
|
|||
// Skip functions that consist of a docstring and a return statement.
|
||||
if body.len() == 2 {
|
||||
if let Stmt::Expr(ast::StmtExpr { value, range: _ }) = &body[0] {
|
||||
if matches!(
|
||||
value.as_ref(),
|
||||
Expr::Constant(ast::ExprConstant {
|
||||
value: Constant::Str(_),
|
||||
..
|
||||
})
|
||||
) {
|
||||
if value.is_string_literal_expr() {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
//! Settings for the `pylint` plugin.
|
||||
|
||||
use anyhow::anyhow;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use ruff_macros::CacheKey;
|
||||
use ruff_python_ast::Constant;
|
||||
use ruff_python_ast::{Expr, ExprNumberLiteral, Number};
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Serialize, Deserialize, CacheKey)]
|
||||
#[serde(deny_unknown_fields, rename_all = "kebab-case")]
|
||||
|
@ -17,19 +16,17 @@ pub enum ConstantType {
|
|||
Str,
|
||||
}
|
||||
|
||||
impl TryFrom<&Constant> for ConstantType {
|
||||
type Error = anyhow::Error;
|
||||
|
||||
fn try_from(value: &Constant) -> Result<Self, Self::Error> {
|
||||
match value {
|
||||
Constant::Bytes(..) => Ok(Self::Bytes),
|
||||
Constant::Complex { .. } => Ok(Self::Complex),
|
||||
Constant::Float(..) => Ok(Self::Float),
|
||||
Constant::Int(..) => Ok(Self::Int),
|
||||
Constant::Str(..) => Ok(Self::Str),
|
||||
Constant::Bool(..) | Constant::Ellipsis | Constant::None => {
|
||||
Err(anyhow!("Singleton constants are unsupported"))
|
||||
}
|
||||
impl ConstantType {
|
||||
pub fn try_from_expr(expr: &Expr) -> Option<Self> {
|
||||
match expr {
|
||||
Expr::StringLiteral(_) => Some(Self::Str),
|
||||
Expr::BytesLiteral(_) => Some(Self::Bytes),
|
||||
Expr::NumberLiteral(ExprNumberLiteral { value, .. }) => match value {
|
||||
Number::Int(_) => Some(Self::Int),
|
||||
Number::Float(_) => Some(Self::Float),
|
||||
Number::Complex { .. } => Some(Self::Complex),
|
||||
},
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,9 +3,7 @@ use log::debug;
|
|||
use ruff_diagnostics::{Diagnostic, Edit, Fix, FixAvailability, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
use ruff_python_ast::helpers::is_dunder;
|
||||
use ruff_python_ast::{
|
||||
self as ast, Arguments, Constant, Expr, ExprContext, Identifier, Keyword, Stmt,
|
||||
};
|
||||
use ruff_python_ast::{self as ast, Arguments, Expr, ExprContext, Identifier, Keyword, Stmt};
|
||||
use ruff_python_codegen::Generator;
|
||||
use ruff_python_semantic::SemanticModel;
|
||||
use ruff_python_stdlib::identifiers::is_identifier;
|
||||
|
@ -183,10 +181,7 @@ fn create_fields_from_fields_arg(fields: &Expr) -> Option<Vec<Stmt>> {
|
|||
let [field, annotation] = elts.as_slice() else {
|
||||
return None;
|
||||
};
|
||||
let field = field.as_constant_expr()?;
|
||||
let Constant::Str(ast::StringConstant { value: field, .. }) = &field.value else {
|
||||
return None;
|
||||
};
|
||||
let ast::ExprStringLiteral { value: field, .. } = field.as_string_literal_expr()?;
|
||||
if !is_identifier(field) {
|
||||
return None;
|
||||
}
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
use ruff_diagnostics::{Diagnostic, Edit, Fix, FixAvailability, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
use ruff_python_ast::helpers::is_dunder;
|
||||
use ruff_python_ast::{
|
||||
self as ast, Arguments, Constant, Expr, ExprContext, Identifier, Keyword, Stmt,
|
||||
};
|
||||
use ruff_python_ast::{self as ast, Arguments, Expr, ExprContext, Identifier, Keyword, Stmt};
|
||||
use ruff_python_codegen::Generator;
|
||||
use ruff_python_semantic::SemanticModel;
|
||||
use ruff_python_stdlib::identifiers::is_identifier;
|
||||
|
@ -175,10 +173,7 @@ fn fields_from_dict_literal(keys: &[Option<Expr>], values: &[Expr]) -> Option<Ve
|
|||
keys.iter()
|
||||
.zip(values.iter())
|
||||
.map(|(key, value)| match key {
|
||||
Some(Expr::Constant(ast::ExprConstant {
|
||||
value: Constant::Str(ast::StringConstant { value: field, .. }),
|
||||
..
|
||||
})) => {
|
||||
Some(Expr::StringLiteral(ast::ExprStringLiteral { value: field, .. })) => {
|
||||
if !is_identifier(field) {
|
||||
return None;
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@ use rustc_hash::FxHashMap;
|
|||
use ruff_diagnostics::{Diagnostic, Edit, Fix, FixAvailability, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
use ruff_python_ast::str::{leading_quote, trailing_quote};
|
||||
use ruff_python_ast::{self as ast, Constant, Expr, Keyword};
|
||||
use ruff_python_ast::{self as ast, Expr, Keyword};
|
||||
use ruff_python_literal::format::{
|
||||
FieldName, FieldNamePart, FieldType, FormatPart, FormatString, FromTemplate,
|
||||
};
|
||||
|
@ -159,8 +159,8 @@ fn formatted_expr<'a>(expr: &Expr, context: FormatContext, locator: &Locator<'a>
|
|||
// E.g., `12` should be parenthesized in `f"{(12).real}"`.
|
||||
(
|
||||
FormatContext::Accessed,
|
||||
Expr::Constant(ast::ExprConstant {
|
||||
value: Constant::Int(..),
|
||||
Expr::NumberLiteral(ast::ExprNumberLiteral {
|
||||
value: ast::Number::Int(..),
|
||||
..
|
||||
}),
|
||||
) => text.chars().all(|c| c.is_ascii_digit()),
|
||||
|
@ -314,13 +314,7 @@ pub(crate) fn f_strings(
|
|||
return;
|
||||
};
|
||||
|
||||
if !matches!(
|
||||
value.as_ref(),
|
||||
Expr::Constant(ast::ExprConstant {
|
||||
value: Constant::Str(..),
|
||||
..
|
||||
}),
|
||||
) {
|
||||
if !value.is_string_literal_expr() {
|
||||
return;
|
||||
};
|
||||
|
||||
|
|
|
@ -3,8 +3,8 @@ use std::str::FromStr;
|
|||
|
||||
use ruff_diagnostics::{AlwaysFixableViolation, Diagnostic, Edit, Fix};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
use ruff_python_ast::{self as ast, Constant, Expr};
|
||||
use ruff_text_size::Ranged;
|
||||
use ruff_python_ast::{self as ast, Expr};
|
||||
use ruff_text_size::{Ranged, TextRange};
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
|
||||
|
@ -32,35 +32,54 @@ impl FromStr for LiteralType {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<LiteralType> for Constant {
|
||||
fn from(value: LiteralType) -> Self {
|
||||
match value {
|
||||
LiteralType::Str => Constant::Str(ast::StringConstant {
|
||||
impl LiteralType {
|
||||
fn as_zero_value_expr(self) -> Expr {
|
||||
match self {
|
||||
LiteralType::Str => ast::ExprStringLiteral {
|
||||
value: String::new(),
|
||||
unicode: false,
|
||||
implicit_concatenated: false,
|
||||
}),
|
||||
LiteralType::Bytes => Constant::Bytes(ast::BytesConstant {
|
||||
range: TextRange::default(),
|
||||
}
|
||||
.into(),
|
||||
LiteralType::Bytes => ast::ExprBytesLiteral {
|
||||
value: Vec::new(),
|
||||
implicit_concatenated: false,
|
||||
}),
|
||||
LiteralType::Int => Constant::Int(0.into()),
|
||||
LiteralType::Float => Constant::Float(0.0),
|
||||
LiteralType::Bool => Constant::Bool(false),
|
||||
range: TextRange::default(),
|
||||
}
|
||||
.into(),
|
||||
LiteralType::Int => ast::ExprNumberLiteral {
|
||||
value: ast::Number::Int(0.into()),
|
||||
range: TextRange::default(),
|
||||
}
|
||||
.into(),
|
||||
LiteralType::Float => ast::ExprNumberLiteral {
|
||||
value: ast::Number::Float(0.0),
|
||||
range: TextRange::default(),
|
||||
}
|
||||
.into(),
|
||||
LiteralType::Bool => ast::ExprBooleanLiteral {
|
||||
value: false,
|
||||
range: TextRange::default(),
|
||||
}
|
||||
.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&Constant> for LiteralType {
|
||||
impl TryFrom<&Expr> for LiteralType {
|
||||
type Error = ();
|
||||
|
||||
fn try_from(value: &Constant) -> Result<Self, Self::Error> {
|
||||
match value {
|
||||
Constant::Str(_) => Ok(LiteralType::Str),
|
||||
Constant::Bytes(_) => Ok(LiteralType::Bytes),
|
||||
Constant::Int(_) => Ok(LiteralType::Int),
|
||||
Constant::Float(_) => Ok(LiteralType::Float),
|
||||
Constant::Bool(_) => Ok(LiteralType::Bool),
|
||||
fn try_from(expr: &Expr) -> Result<Self, Self::Error> {
|
||||
match expr {
|
||||
Expr::StringLiteral(_) => Ok(LiteralType::Str),
|
||||
Expr::BytesLiteral(_) => Ok(LiteralType::Bytes),
|
||||
Expr::NumberLiteral(ast::ExprNumberLiteral { value, .. }) => match value {
|
||||
ast::Number::Int(_) => Ok(LiteralType::Int),
|
||||
ast::Number::Float(_) => Ok(LiteralType::Float),
|
||||
ast::Number::Complex { .. } => Err(()),
|
||||
},
|
||||
Expr::BooleanLiteral(_) => Ok(LiteralType::Bool),
|
||||
_ => Err(()),
|
||||
}
|
||||
}
|
||||
|
@ -181,8 +200,8 @@ pub(crate) fn native_literals(
|
|||
return;
|
||||
}
|
||||
|
||||
let constant = Constant::from(literal_type);
|
||||
let content = checker.generator().constant(&constant);
|
||||
let expr = literal_type.as_zero_value_expr();
|
||||
let content = checker.generator().expr(&expr);
|
||||
diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement(
|
||||
content,
|
||||
call.range(),
|
||||
|
@ -190,16 +209,12 @@ pub(crate) fn native_literals(
|
|||
checker.diagnostics.push(diagnostic);
|
||||
}
|
||||
Some(arg) => {
|
||||
let Expr::Constant(ast::ExprConstant { value, .. }) = arg else {
|
||||
return;
|
||||
};
|
||||
|
||||
// Skip implicit string concatenations.
|
||||
if value.is_implicit_concatenated() {
|
||||
if arg.is_implicit_concatenated_string() {
|
||||
return;
|
||||
}
|
||||
|
||||
let Ok(arg_literal_type) = LiteralType::try_from(value) else {
|
||||
let Ok(arg_literal_type) = LiteralType::try_from(arg) else {
|
||||
return;
|
||||
};
|
||||
|
||||
|
@ -213,8 +228,14 @@ pub(crate) fn native_literals(
|
|||
// Ex) `(7).denominator` is valid but `7.denominator` is not
|
||||
// Note that floats do not have this problem
|
||||
// Ex) `(1.0).real` is valid and `1.0.real` is too
|
||||
let content = match (parent_expr, value) {
|
||||
(Some(Expr::Attribute(_)), Constant::Int(_)) => format!("({arg_code})"),
|
||||
let content = match (parent_expr, arg) {
|
||||
(
|
||||
Some(Expr::Attribute(_)),
|
||||
Expr::NumberLiteral(ast::ExprNumberLiteral {
|
||||
value: ast::Number::Int(_),
|
||||
..
|
||||
}),
|
||||
) => format!("({arg_code})"),
|
||||
_ => arg_code.to_string(),
|
||||
};
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ use ruff_macros::{derive_message_formats, violation};
|
|||
use ruff_python_ast::helpers::map_subscript;
|
||||
use ruff_python_ast::stmt_if::{if_elif_branches, BranchKind, IfElifBranch};
|
||||
use ruff_python_ast::whitespace::indentation;
|
||||
use ruff_python_ast::{self as ast, CmpOp, Constant, ElifElseClause, Expr, Int, StmtIf};
|
||||
use ruff_python_ast::{self as ast, CmpOp, ElifElseClause, Expr, Int, StmtIf};
|
||||
use ruff_text_size::{Ranged, TextLen, TextRange};
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
|
@ -147,8 +147,8 @@ pub(crate) fn outdated_version_block(checker: &mut Checker, stmt_if: &StmtIf) {
|
|||
}
|
||||
_ => {}
|
||||
},
|
||||
Expr::Constant(ast::ExprConstant {
|
||||
value: Constant::Int(int),
|
||||
Expr::NumberLiteral(ast::ExprNumberLiteral {
|
||||
value: ast::Number::Int(int),
|
||||
..
|
||||
}) => {
|
||||
if op == &CmpOp::Eq {
|
||||
|
@ -409,8 +409,8 @@ fn fix_always_true_branch(
|
|||
fn extract_version(elts: &[Expr]) -> Option<Vec<Int>> {
|
||||
let mut version: Vec<Int> = vec![];
|
||||
for elt in elts {
|
||||
let Expr::Constant(ast::ExprConstant {
|
||||
value: Constant::Int(int),
|
||||
let Expr::NumberLiteral(ast::ExprNumberLiteral {
|
||||
value: ast::Number::Int(int),
|
||||
..
|
||||
}) = &elt
|
||||
else {
|
||||
|
|
|
@ -5,7 +5,7 @@ use ruff_diagnostics::{Diagnostic, Edit, Fix, FixAvailability, Violation};
|
|||
use ruff_macros::{derive_message_formats, violation};
|
||||
use ruff_python_ast::str::{leading_quote, trailing_quote};
|
||||
use ruff_python_ast::whitespace::indentation;
|
||||
use ruff_python_ast::{self as ast, Constant, Expr};
|
||||
use ruff_python_ast::{self as ast, Expr};
|
||||
use ruff_python_codegen::Stylist;
|
||||
use ruff_python_literal::cformat::{
|
||||
CConversionFlags, CFormatPart, CFormatPrecision, CFormatQuantity, CFormatString,
|
||||
|
@ -223,12 +223,8 @@ fn clean_params_dictionary(right: &Expr, locator: &Locator, stylist: &Stylist) -
|
|||
for (key, value) in keys.iter().zip(values.iter()) {
|
||||
match key {
|
||||
Some(key) => {
|
||||
if let Expr::Constant(ast::ExprConstant {
|
||||
value:
|
||||
Constant::Str(ast::StringConstant {
|
||||
value: key_string, ..
|
||||
}),
|
||||
..
|
||||
if let Expr::StringLiteral(ast::ExprStringLiteral {
|
||||
value: key_string, ..
|
||||
}) = key
|
||||
{
|
||||
// If the dictionary key is not a valid variable name, abort.
|
||||
|
@ -420,9 +416,13 @@ pub(crate) fn printf_string_formatting(checker: &mut Checker, expr: &Expr, right
|
|||
|
||||
// Parse the parameters.
|
||||
let params_string = match right {
|
||||
Expr::Constant(_) | Expr::FString(_) => {
|
||||
Cow::Owned(format!("({})", checker.locator().slice(right)))
|
||||
}
|
||||
Expr::StringLiteral(_)
|
||||
| Expr::BytesLiteral(_)
|
||||
| Expr::NumberLiteral(_)
|
||||
| Expr::BooleanLiteral(_)
|
||||
| Expr::NoneLiteral(_)
|
||||
| Expr::EllipsisLiteral(_)
|
||||
| Expr::FString(_) => Cow::Owned(format!("({})", checker.locator().slice(right))),
|
||||
Expr::Name(_) | Expr::Attribute(_) | Expr::Subscript(_) | Expr::Call(_) => {
|
||||
if num_keyword_arguments > 0 {
|
||||
// If we have _any_ named fields, assume the right-hand side is a mapping.
|
||||
|
|
|
@ -4,7 +4,7 @@ use anyhow::{anyhow, Result};
|
|||
|
||||
use ruff_diagnostics::{AlwaysFixableViolation, Diagnostic, Edit, Fix};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
use ruff_python_ast::{self as ast, Constant, Expr, PySourceType};
|
||||
use ruff_python_ast::{self as ast, Expr, PySourceType};
|
||||
use ruff_python_parser::{lexer, AsMode};
|
||||
use ruff_python_semantic::SemanticModel;
|
||||
use ruff_source_file::Locator;
|
||||
|
@ -71,12 +71,8 @@ pub(crate) fn redundant_open_modes(checker: &mut Checker, call: &ast::ExprCall)
|
|||
None => {
|
||||
if !call.arguments.is_empty() {
|
||||
if let Some(keyword) = call.arguments.find_keyword(MODE_KEYWORD_ARGUMENT) {
|
||||
if let Expr::Constant(ast::ExprConstant {
|
||||
value:
|
||||
Constant::Str(ast::StringConstant {
|
||||
value: mode_param_value,
|
||||
..
|
||||
}),
|
||||
if let Expr::StringLiteral(ast::ExprStringLiteral {
|
||||
value: mode_param_value,
|
||||
..
|
||||
}) = &keyword.value
|
||||
{
|
||||
|
@ -94,11 +90,7 @@ pub(crate) fn redundant_open_modes(checker: &mut Checker, call: &ast::ExprCall)
|
|||
}
|
||||
}
|
||||
Some(mode_param) => {
|
||||
if let Expr::Constant(ast::ExprConstant {
|
||||
value: Constant::Str(value),
|
||||
..
|
||||
}) = &mode_param
|
||||
{
|
||||
if let Expr::StringLiteral(ast::ExprStringLiteral { value, .. }) = &mode_param {
|
||||
if let Ok(mode) = OpenMode::from_str(value) {
|
||||
checker.diagnostics.push(create_check(
|
||||
call,
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use ruff_python_ast::{self as ast, Expr};
|
||||
use ruff_python_ast::Expr;
|
||||
|
||||
use crate::fix::edits::pad;
|
||||
use ruff_diagnostics::{Diagnostic, Edit, Fix, FixAvailability, Violation};
|
||||
|
@ -65,10 +65,7 @@ pub(crate) fn type_of_primitive(checker: &mut Checker, expr: &Expr, func: &Expr,
|
|||
{
|
||||
return;
|
||||
}
|
||||
let Expr::Constant(ast::ExprConstant { value, .. }) = &arg else {
|
||||
return;
|
||||
};
|
||||
let Some(primitive) = Primitive::from_constant(value) else {
|
||||
let Some(primitive) = Primitive::from_expr(arg) else {
|
||||
return;
|
||||
};
|
||||
let mut diagnostic = Diagnostic::new(TypeOfPrimitive { primitive }, expr.range());
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use ruff_diagnostics::{AlwaysFixableViolation, Diagnostic, Edit, Fix};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
use ruff_python_ast::Expr;
|
||||
use ruff_python_ast::ExprStringLiteral;
|
||||
use ruff_text_size::{Ranged, TextRange, TextSize};
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
|
@ -39,11 +39,11 @@ impl AlwaysFixableViolation for UnicodeKindPrefix {
|
|||
}
|
||||
|
||||
/// UP025
|
||||
pub(crate) fn unicode_kind_prefix(checker: &mut Checker, expr: &Expr, is_unicode: bool) {
|
||||
if is_unicode {
|
||||
let mut diagnostic = Diagnostic::new(UnicodeKindPrefix, expr.range());
|
||||
pub(crate) fn unicode_kind_prefix(checker: &mut Checker, string: &ExprStringLiteral) {
|
||||
if string.unicode {
|
||||
let mut diagnostic = Diagnostic::new(UnicodeKindPrefix, string.range);
|
||||
diagnostic.set_fix(Fix::safe_edit(Edit::range_deletion(TextRange::at(
|
||||
expr.start(),
|
||||
string.start(),
|
||||
TextSize::from(1),
|
||||
))));
|
||||
checker.diagnostics.push(diagnostic);
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use ruff_diagnostics::{AlwaysFixableViolation, Diagnostic, Edit, Fix};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
use ruff_python_ast::{self as ast, Arguments, Constant, Expr, Keyword, PySourceType};
|
||||
use ruff_python_ast::{self as ast, Arguments, Expr, Keyword, PySourceType};
|
||||
use ruff_python_parser::{lexer, AsMode, Tok};
|
||||
use ruff_source_file::Locator;
|
||||
use ruff_text_size::{Ranged, TextRange};
|
||||
|
@ -73,11 +73,7 @@ fn match_encoded_variable(func: &Expr) -> Option<&Expr> {
|
|||
}
|
||||
|
||||
fn is_utf8_encoding_arg(arg: &Expr) -> bool {
|
||||
if let Expr::Constant(ast::ExprConstant {
|
||||
value: Constant::Str(value),
|
||||
..
|
||||
}) = &arg
|
||||
{
|
||||
if let Expr::StringLiteral(ast::ExprStringLiteral { value, .. }) = &arg {
|
||||
UTF8_LITERALS.contains(&value.to_lowercase().as_str())
|
||||
} else {
|
||||
false
|
||||
|
@ -162,10 +158,7 @@ pub(crate) fn unnecessary_encode_utf8(checker: &mut Checker, call: &ast::ExprCal
|
|||
return;
|
||||
};
|
||||
match variable {
|
||||
Expr::Constant(ast::ExprConstant {
|
||||
value: Constant::Str(literal),
|
||||
..
|
||||
}) => {
|
||||
Expr::StringLiteral(ast::ExprStringLiteral { value: literal, .. }) => {
|
||||
// Ex) `"str".encode()`, `"str".encode("utf-8")`
|
||||
if let Some(encoding_arg) = match_encoding_arg(&call.arguments) {
|
||||
if literal.is_ascii() {
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue