mirror of https://github.com/astral-sh/ruff
Truncate some messages in diagnostics (#6748)
## Summary I noticed this in the ecosystem CI check from https://github.com/astral-sh/ruff/pull/6742. If we include source code directly in a diagnostic, we need to be careful to avoid rendering multi-line diagnostics or even excessively long diagnostics. ## Test Plan `cargo test`
This commit is contained in:
parent
0aad0c41f6
commit
fa32cd9b6f
|
|
@ -13,6 +13,7 @@ use crate::registry::{AsRule, Rule};
|
||||||
|
|
||||||
pub(crate) mod codemods;
|
pub(crate) mod codemods;
|
||||||
pub(crate) mod edits;
|
pub(crate) mod edits;
|
||||||
|
pub(crate) mod snippet;
|
||||||
pub(crate) mod source_map;
|
pub(crate) mod source_map;
|
||||||
|
|
||||||
pub(crate) struct FixResult {
|
pub(crate) struct FixResult {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,36 @@
|
||||||
|
use unicode_width::UnicodeWidthStr;
|
||||||
|
|
||||||
|
/// A snippet of source code for user-facing display, as in a diagnostic.
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
pub(crate) struct SourceCodeSnippet(String);
|
||||||
|
|
||||||
|
impl SourceCodeSnippet {
|
||||||
|
pub(crate) fn new(source_code: String) -> Self {
|
||||||
|
Self(source_code)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return the full snippet for user-facing display, or `None` if the snippet should be
|
||||||
|
/// truncated.
|
||||||
|
pub(crate) fn full_display(&self) -> Option<&str> {
|
||||||
|
if Self::should_truncate(&self.0) {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(&self.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return a truncated snippet for user-facing display.
|
||||||
|
pub(crate) fn truncated_display(&self) -> &str {
|
||||||
|
if Self::should_truncate(&self.0) {
|
||||||
|
"..."
|
||||||
|
} else {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns `true` if the source code should be truncated when included in a user-facing
|
||||||
|
/// diagnostic.
|
||||||
|
fn should_truncate(source_code: &str) -> bool {
|
||||||
|
source_code.width() > 50 || source_code.contains(['\r', '\n'])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,14 +1,15 @@
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use libcst_native::CompOp;
|
use libcst_native::CompOp;
|
||||||
use ruff_python_ast::{self as ast, CmpOp, Expr, Ranged, UnaryOp};
|
|
||||||
|
|
||||||
use crate::autofix::codemods::CodegenStylist;
|
|
||||||
use ruff_diagnostics::{AutofixKind, Diagnostic, Edit, Fix, Violation};
|
use ruff_diagnostics::{AutofixKind, Diagnostic, Edit, Fix, Violation};
|
||||||
use ruff_macros::{derive_message_formats, violation};
|
use ruff_macros::{derive_message_formats, violation};
|
||||||
|
use ruff_python_ast::{self as ast, CmpOp, Expr, Ranged, UnaryOp};
|
||||||
use ruff_python_codegen::Stylist;
|
use ruff_python_codegen::Stylist;
|
||||||
use ruff_python_stdlib::str::{self};
|
use ruff_python_stdlib::str::{self};
|
||||||
use ruff_source_file::Locator;
|
use ruff_source_file::Locator;
|
||||||
|
|
||||||
|
use crate::autofix::codemods::CodegenStylist;
|
||||||
|
use crate::autofix::snippet::SourceCodeSnippet;
|
||||||
use crate::checkers::ast::Checker;
|
use crate::checkers::ast::Checker;
|
||||||
use crate::cst::matchers::{match_comparison, match_expression};
|
use crate::cst::matchers::{match_comparison, match_expression};
|
||||||
use crate::registry::AsRule;
|
use crate::registry::AsRule;
|
||||||
|
|
@ -45,7 +46,7 @@ use crate::registry::AsRule;
|
||||||
/// - [Python documentation: Assignment statements](https://docs.python.org/3/reference/simple_stmts.html#assignment-statements)
|
/// - [Python documentation: Assignment statements](https://docs.python.org/3/reference/simple_stmts.html#assignment-statements)
|
||||||
#[violation]
|
#[violation]
|
||||||
pub struct YodaConditions {
|
pub struct YodaConditions {
|
||||||
pub suggestion: Option<String>,
|
suggestion: Option<SourceCodeSnippet>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Violation for YodaConditions {
|
impl Violation for YodaConditions {
|
||||||
|
|
@ -54,7 +55,10 @@ impl Violation for YodaConditions {
|
||||||
#[derive_message_formats]
|
#[derive_message_formats]
|
||||||
fn message(&self) -> String {
|
fn message(&self) -> String {
|
||||||
let YodaConditions { suggestion } = self;
|
let YodaConditions { suggestion } = self;
|
||||||
if let Some(suggestion) = suggestion {
|
if let Some(suggestion) = suggestion
|
||||||
|
.as_ref()
|
||||||
|
.and_then(SourceCodeSnippet::full_display)
|
||||||
|
{
|
||||||
format!("Yoda conditions are discouraged, use `{suggestion}` instead")
|
format!("Yoda conditions are discouraged, use `{suggestion}` instead")
|
||||||
} else {
|
} else {
|
||||||
format!("Yoda conditions are discouraged")
|
format!("Yoda conditions are discouraged")
|
||||||
|
|
@ -63,9 +67,13 @@ impl Violation for YodaConditions {
|
||||||
|
|
||||||
fn autofix_title(&self) -> Option<String> {
|
fn autofix_title(&self) -> Option<String> {
|
||||||
let YodaConditions { suggestion } = self;
|
let YodaConditions { suggestion } = self;
|
||||||
suggestion
|
suggestion.as_ref().map(|suggestion| {
|
||||||
.as_ref()
|
if let Some(suggestion) = suggestion.full_display() {
|
||||||
.map(|suggestion| format!("Replace Yoda condition with `{suggestion}`"))
|
format!("Replace Yoda condition with `{suggestion}`")
|
||||||
|
} else {
|
||||||
|
format!("Replace Yoda condition")
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -178,7 +186,7 @@ pub(crate) fn yoda_conditions(
|
||||||
if let Ok(suggestion) = reverse_comparison(expr, checker.locator(), checker.stylist()) {
|
if let Ok(suggestion) = reverse_comparison(expr, checker.locator(), checker.stylist()) {
|
||||||
let mut diagnostic = Diagnostic::new(
|
let mut diagnostic = Diagnostic::new(
|
||||||
YodaConditions {
|
YodaConditions {
|
||||||
suggestion: Some(suggestion.to_string()),
|
suggestion: Some(SourceCodeSnippet::new(suggestion.clone())),
|
||||||
},
|
},
|
||||||
expr.range(),
|
expr.range(),
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -290,7 +290,7 @@ SIM300.py:15:1: SIM300 [*] Yoda conditions are discouraged, use `(number - 100)
|
||||||
17 17 |
|
17 17 |
|
||||||
18 18 | # OK
|
18 18 | # OK
|
||||||
|
|
||||||
SIM300.py:16:1: SIM300 [*] Yoda conditions are discouraged, use `(60 * 60) < SomeClass().settings.SOME_CONSTANT_VALUE` instead
|
SIM300.py:16:1: SIM300 [*] Yoda conditions are discouraged
|
||||||
|
|
|
|
||||||
14 | JediOrder.YODA == age # SIM300
|
14 | JediOrder.YODA == age # SIM300
|
||||||
15 | 0 < (number - 100) # SIM300
|
15 | 0 < (number - 100) # SIM300
|
||||||
|
|
@ -299,7 +299,7 @@ SIM300.py:16:1: SIM300 [*] Yoda conditions are discouraged, use `(60 * 60) < Som
|
||||||
17 |
|
17 |
|
||||||
18 | # OK
|
18 | # OK
|
||||||
|
|
|
|
||||||
= help: Replace Yoda condition with `(60 * 60) < SomeClass().settings.SOME_CONSTANT_VALUE`
|
= help: Replace Yoda condition
|
||||||
|
|
||||||
ℹ Fix
|
ℹ Fix
|
||||||
13 13 | YODA >= age # SIM300
|
13 13 | YODA >= age # SIM300
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,11 @@
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use ruff_python_ast::{self as ast, Arguments, Constant, Expr, Ranged};
|
|
||||||
use ruff_text_size::TextRange;
|
|
||||||
|
|
||||||
use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic, Edit, Fix};
|
use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic, Edit, Fix};
|
||||||
use ruff_macros::{derive_message_formats, violation};
|
use ruff_macros::{derive_message_formats, violation};
|
||||||
|
use ruff_python_ast::{self as ast, Arguments, Constant, Expr, Ranged};
|
||||||
|
use ruff_text_size::TextRange;
|
||||||
|
|
||||||
|
use crate::autofix::snippet::SourceCodeSnippet;
|
||||||
use crate::checkers::ast::Checker;
|
use crate::checkers::ast::Checker;
|
||||||
use crate::registry::AsRule;
|
use crate::registry::AsRule;
|
||||||
use crate::rules::flynt::helpers;
|
use crate::rules::flynt::helpers;
|
||||||
|
|
@ -29,19 +30,27 @@ use crate::rules::flynt::helpers;
|
||||||
/// - [Python documentation: f-strings](https://docs.python.org/3/reference/lexical_analysis.html#f-strings)
|
/// - [Python documentation: f-strings](https://docs.python.org/3/reference/lexical_analysis.html#f-strings)
|
||||||
#[violation]
|
#[violation]
|
||||||
pub struct StaticJoinToFString {
|
pub struct StaticJoinToFString {
|
||||||
expr: String,
|
expression: SourceCodeSnippet,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AlwaysAutofixableViolation for StaticJoinToFString {
|
impl AlwaysAutofixableViolation for StaticJoinToFString {
|
||||||
#[derive_message_formats]
|
#[derive_message_formats]
|
||||||
fn message(&self) -> String {
|
fn message(&self) -> String {
|
||||||
let StaticJoinToFString { expr } = self;
|
let StaticJoinToFString { expression } = self;
|
||||||
format!("Consider `{expr}` instead of string join")
|
if let Some(expression) = expression.full_display() {
|
||||||
|
format!("Consider `{expression}` instead of string join")
|
||||||
|
} else {
|
||||||
|
format!("Consider f-string instead of string join")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn autofix_title(&self) -> String {
|
fn autofix_title(&self) -> String {
|
||||||
let StaticJoinToFString { expr } = self;
|
let StaticJoinToFString { expression } = self;
|
||||||
format!("Replace with `{expr}`")
|
if let Some(expression) = expression.full_display() {
|
||||||
|
format!("Replace with `{expression}`")
|
||||||
|
} else {
|
||||||
|
format!("Replace with f-string")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -140,7 +149,7 @@ pub(crate) fn static_join_to_fstring(checker: &mut Checker, expr: &Expr, joiner:
|
||||||
|
|
||||||
let mut diagnostic = Diagnostic::new(
|
let mut diagnostic = Diagnostic::new(
|
||||||
StaticJoinToFString {
|
StaticJoinToFString {
|
||||||
expr: contents.clone(),
|
expression: SourceCodeSnippet::new(contents.clone()),
|
||||||
},
|
},
|
||||||
expr.range(),
|
expr.range(),
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,8 @@ pub struct BadStringFormatCharacter {
|
||||||
impl Violation for BadStringFormatCharacter {
|
impl Violation for BadStringFormatCharacter {
|
||||||
#[derive_message_formats]
|
#[derive_message_formats]
|
||||||
fn message(&self) -> String {
|
fn message(&self) -> String {
|
||||||
format!("Unsupported format character '{}'", self.format_char)
|
let BadStringFormatCharacter { format_char } = self;
|
||||||
|
format!("Unsupported format character '{format_char}'")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ use itertools::{any, Itertools};
|
||||||
use ruff_python_ast::{BoolOp, CmpOp, Expr, ExprBoolOp, ExprCompare, Ranged};
|
use ruff_python_ast::{BoolOp, CmpOp, Expr, ExprBoolOp, ExprCompare, Ranged};
|
||||||
use rustc_hash::FxHashMap;
|
use rustc_hash::FxHashMap;
|
||||||
|
|
||||||
|
use crate::autofix::snippet::SourceCodeSnippet;
|
||||||
use ruff_diagnostics::{Diagnostic, Violation};
|
use ruff_diagnostics::{Diagnostic, Violation};
|
||||||
use ruff_macros::{derive_message_formats, violation};
|
use ruff_macros::{derive_message_formats, violation};
|
||||||
use ruff_python_ast::hashable::HashableExpr;
|
use ruff_python_ast::hashable::HashableExpr;
|
||||||
|
|
@ -42,16 +43,22 @@ use crate::checkers::ast::Checker;
|
||||||
/// - [Python documentation: `set`](https://docs.python.org/3/library/stdtypes.html#set)
|
/// - [Python documentation: `set`](https://docs.python.org/3/library/stdtypes.html#set)
|
||||||
#[violation]
|
#[violation]
|
||||||
pub struct RepeatedEqualityComparisonTarget {
|
pub struct RepeatedEqualityComparisonTarget {
|
||||||
expr: String,
|
expression: SourceCodeSnippet,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Violation for RepeatedEqualityComparisonTarget {
|
impl Violation for RepeatedEqualityComparisonTarget {
|
||||||
#[derive_message_formats]
|
#[derive_message_formats]
|
||||||
fn message(&self) -> String {
|
fn message(&self) -> String {
|
||||||
let RepeatedEqualityComparisonTarget { expr } = self;
|
let RepeatedEqualityComparisonTarget { expression } = self;
|
||||||
format!(
|
if let Some(expression) = expression.full_display() {
|
||||||
"Consider merging multiple comparisons: `{expr}`. Use a `set` if the elements are hashable."
|
format!(
|
||||||
)
|
"Consider merging multiple comparisons: `{expression}`. Use a `set` if the elements are hashable."
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
format!(
|
||||||
|
"Consider merging multiple comparisons. Use a `set` if the elements are hashable."
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -84,12 +91,12 @@ pub(crate) fn repeated_equality_comparison_target(checker: &mut Checker, bool_op
|
||||||
if count > 1 {
|
if count > 1 {
|
||||||
checker.diagnostics.push(Diagnostic::new(
|
checker.diagnostics.push(Diagnostic::new(
|
||||||
RepeatedEqualityComparisonTarget {
|
RepeatedEqualityComparisonTarget {
|
||||||
expr: merged_membership_test(
|
expression: SourceCodeSnippet::new(merged_membership_test(
|
||||||
left.as_expr(),
|
left.as_expr(),
|
||||||
bool_op.op,
|
bool_op.op,
|
||||||
&comparators,
|
&comparators,
|
||||||
checker.locator(),
|
checker.locator(),
|
||||||
),
|
)),
|
||||||
},
|
},
|
||||||
bool_op.range(),
|
bool_op.range(),
|
||||||
));
|
));
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
|
use ruff_diagnostics::{AutofixKind, Diagnostic, Edit, Fix, Violation};
|
||||||
|
use ruff_macros::{derive_message_formats, violation};
|
||||||
use ruff_python_ast::{self as ast, Expr, ExprContext, Operator, Ranged};
|
use ruff_python_ast::{self as ast, Expr, ExprContext, Operator, Ranged};
|
||||||
use ruff_text_size::TextRange;
|
use ruff_text_size::TextRange;
|
||||||
|
|
||||||
use ruff_diagnostics::{AutofixKind, Diagnostic, Edit, Fix, Violation};
|
use crate::autofix::snippet::SourceCodeSnippet;
|
||||||
use ruff_macros::{derive_message_formats, violation};
|
|
||||||
|
|
||||||
use crate::checkers::ast::Checker;
|
use crate::checkers::ast::Checker;
|
||||||
use crate::registry::AsRule;
|
use crate::registry::AsRule;
|
||||||
|
|
||||||
|
|
@ -39,7 +39,7 @@ use crate::registry::AsRule;
|
||||||
/// - [Python documentation: Sequence Types — `list`, `tuple`, `range`](https://docs.python.org/3/library/stdtypes.html#sequence-types-list-tuple-range)
|
/// - [Python documentation: Sequence Types — `list`, `tuple`, `range`](https://docs.python.org/3/library/stdtypes.html#sequence-types-list-tuple-range)
|
||||||
#[violation]
|
#[violation]
|
||||||
pub struct CollectionLiteralConcatenation {
|
pub struct CollectionLiteralConcatenation {
|
||||||
expr: String,
|
expression: SourceCodeSnippet,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Violation for CollectionLiteralConcatenation {
|
impl Violation for CollectionLiteralConcatenation {
|
||||||
|
|
@ -47,13 +47,21 @@ impl Violation for CollectionLiteralConcatenation {
|
||||||
|
|
||||||
#[derive_message_formats]
|
#[derive_message_formats]
|
||||||
fn message(&self) -> String {
|
fn message(&self) -> String {
|
||||||
let CollectionLiteralConcatenation { expr } = self;
|
let CollectionLiteralConcatenation { expression } = self;
|
||||||
format!("Consider `{expr}` instead of concatenation")
|
if let Some(expression) = expression.full_display() {
|
||||||
|
format!("Consider `{expression}` instead of concatenation")
|
||||||
|
} else {
|
||||||
|
format!("Consider iterable unpacking instead of concatenation")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn autofix_title(&self) -> Option<String> {
|
fn autofix_title(&self) -> Option<String> {
|
||||||
let CollectionLiteralConcatenation { expr } = self;
|
let CollectionLiteralConcatenation { expression } = self;
|
||||||
Some(format!("Replace with `{expr}`"))
|
if let Some(expression) = expression.full_display() {
|
||||||
|
Some(format!("Replace with `{expression}`"))
|
||||||
|
} else {
|
||||||
|
Some(format!("Replace with iterable unpacking"))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -186,7 +194,7 @@ pub(crate) fn collection_literal_concatenation(checker: &mut Checker, expr: &Exp
|
||||||
};
|
};
|
||||||
let mut diagnostic = Diagnostic::new(
|
let mut diagnostic = Diagnostic::new(
|
||||||
CollectionLiteralConcatenation {
|
CollectionLiteralConcatenation {
|
||||||
expr: contents.clone(),
|
expression: SourceCodeSnippet::new(contents.clone()),
|
||||||
},
|
},
|
||||||
expr.range(),
|
expr.range(),
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -90,7 +90,8 @@ impl Violation for ImplicitOptional {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn autofix_title(&self) -> Option<String> {
|
fn autofix_title(&self) -> Option<String> {
|
||||||
Some(format!("Convert to `{}`", self.conversion_type))
|
let ImplicitOptional { conversion_type } = self;
|
||||||
|
Some(format!("Convert to `{conversion_type}`"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -40,6 +40,7 @@ impl Violation for InvalidPyprojectToml {
|
||||||
|
|
||||||
#[derive_message_formats]
|
#[derive_message_formats]
|
||||||
fn message(&self) -> String {
|
fn message(&self) -> String {
|
||||||
format!("Failed to parse pyproject.toml: {}", self.message)
|
let InvalidPyprojectToml { message } = self;
|
||||||
|
format!("Failed to parse pyproject.toml: {message}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
|
|
||||||
use num_traits::Zero;
|
use num_traits::Zero;
|
||||||
use unicode_width::UnicodeWidthStr;
|
|
||||||
|
|
||||||
use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic, Edit, Fix};
|
use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic, Edit, Fix};
|
||||||
use ruff_macros::{derive_message_formats, violation};
|
use ruff_macros::{derive_message_formats, violation};
|
||||||
|
|
@ -9,6 +8,7 @@ use ruff_python_ast::{self as ast, Arguments, Comprehension, Constant, Expr, Ran
|
||||||
use ruff_python_semantic::SemanticModel;
|
use ruff_python_semantic::SemanticModel;
|
||||||
use ruff_text_size::{TextRange, TextSize};
|
use ruff_text_size::{TextRange, TextSize};
|
||||||
|
|
||||||
|
use crate::autofix::snippet::SourceCodeSnippet;
|
||||||
use crate::checkers::ast::Checker;
|
use crate::checkers::ast::Checker;
|
||||||
use crate::registry::AsRule;
|
use crate::registry::AsRule;
|
||||||
|
|
||||||
|
|
@ -47,35 +47,24 @@ use crate::registry::AsRule;
|
||||||
/// - [Iterators and Iterables in Python: Run Efficient Iterations](https://realpython.com/python-iterators-iterables/#when-to-use-an-iterator-in-python)
|
/// - [Iterators and Iterables in Python: Run Efficient Iterations](https://realpython.com/python-iterators-iterables/#when-to-use-an-iterator-in-python)
|
||||||
#[violation]
|
#[violation]
|
||||||
pub(crate) struct UnnecessaryIterableAllocationForFirstElement {
|
pub(crate) struct UnnecessaryIterableAllocationForFirstElement {
|
||||||
iterable: String,
|
iterable: SourceCodeSnippet,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AlwaysAutofixableViolation for UnnecessaryIterableAllocationForFirstElement {
|
impl AlwaysAutofixableViolation for UnnecessaryIterableAllocationForFirstElement {
|
||||||
#[derive_message_formats]
|
#[derive_message_formats]
|
||||||
fn message(&self) -> String {
|
fn message(&self) -> String {
|
||||||
let UnnecessaryIterableAllocationForFirstElement { iterable } = self;
|
let UnnecessaryIterableAllocationForFirstElement { iterable } = self;
|
||||||
let iterable = Self::truncate(iterable);
|
let iterable = iterable.truncated_display();
|
||||||
format!("Prefer `next({iterable})` over single element slice")
|
format!("Prefer `next({iterable})` over single element slice")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn autofix_title(&self) -> String {
|
fn autofix_title(&self) -> String {
|
||||||
let UnnecessaryIterableAllocationForFirstElement { iterable } = self;
|
let UnnecessaryIterableAllocationForFirstElement { iterable } = self;
|
||||||
let iterable = Self::truncate(iterable);
|
let iterable = iterable.truncated_display();
|
||||||
format!("Replace with `next({iterable})`")
|
format!("Replace with `next({iterable})`")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl UnnecessaryIterableAllocationForFirstElement {
|
|
||||||
/// If the iterable is too long, or spans multiple lines, truncate it.
|
|
||||||
fn truncate(iterable: &str) -> &str {
|
|
||||||
if iterable.width() > 40 || iterable.contains(['\r', '\n']) {
|
|
||||||
"..."
|
|
||||||
} else {
|
|
||||||
iterable
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// RUF015
|
/// RUF015
|
||||||
pub(crate) fn unnecessary_iterable_allocation_for_first_element(
|
pub(crate) fn unnecessary_iterable_allocation_for_first_element(
|
||||||
checker: &mut Checker,
|
checker: &mut Checker,
|
||||||
|
|
@ -104,7 +93,7 @@ pub(crate) fn unnecessary_iterable_allocation_for_first_element(
|
||||||
|
|
||||||
let mut diagnostic = Diagnostic::new(
|
let mut diagnostic = Diagnostic::new(
|
||||||
UnnecessaryIterableAllocationForFirstElement {
|
UnnecessaryIterableAllocationForFirstElement {
|
||||||
iterable: iterable.to_string(),
|
iterable: SourceCodeSnippet::new(iterable.to_string()),
|
||||||
},
|
},
|
||||||
*range,
|
*range,
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -187,7 +187,7 @@ RUF005.py:47:16: RUF005 [*] Consider `("we all feel", *Fun.words)` instead of co
|
||||||
49 49 | chain = ["a", "b", "c"] + eggs + list(("yes", "no", "pants") + zoob)
|
49 49 | chain = ["a", "b", "c"] + eggs + list(("yes", "no", "pants") + zoob)
|
||||||
50 50 |
|
50 50 |
|
||||||
|
|
||||||
RUF005.py:49:9: RUF005 [*] Consider `["a", "b", "c", *eggs, *list(("yes", "no", "pants") + zoob)]` instead of concatenation
|
RUF005.py:49:9: RUF005 [*] Consider iterable unpacking instead of concatenation
|
||||||
|
|
|
|
||||||
47 | astonishment = ("we all feel",) + Fun.words
|
47 | astonishment = ("we all feel",) + Fun.words
|
||||||
48 |
|
48 |
|
||||||
|
|
@ -196,7 +196,7 @@ RUF005.py:49:9: RUF005 [*] Consider `["a", "b", "c", *eggs, *list(("yes", "no",
|
||||||
50 |
|
50 |
|
||||||
51 | baz = () + zoob
|
51 | baz = () + zoob
|
||||||
|
|
|
|
||||||
= help: Replace with `["a", "b", "c", *eggs, *list(("yes", "no", "pants") + zoob)]`
|
= help: Replace with iterable unpacking
|
||||||
|
|
||||||
ℹ Suggested fix
|
ℹ Suggested fix
|
||||||
46 46 | excitement = ("we all think",) + Fun().yay()
|
46 46 | excitement = ("we all think",) + Fun().yay()
|
||||||
|
|
@ -294,14 +294,14 @@ RUF005.py:56:15: RUF005 [*] Consider `[sys.executable, "-m", "pylint", *args, pa
|
||||||
58 58 | b = a + [2, 3] + [4]
|
58 58 | b = a + [2, 3] + [4]
|
||||||
59 59 |
|
59 59 |
|
||||||
|
|
||||||
RUF005.py:57:21: RUF005 [*] Consider `(sys.executable, "-m", "pylint", *args, path, path2)` instead of concatenation
|
RUF005.py:57:21: RUF005 [*] Consider iterable unpacking instead of concatenation
|
||||||
|
|
|
|
||||||
56 | pylint_call = [sys.executable, "-m", "pylint"] + args + [path]
|
56 | pylint_call = [sys.executable, "-m", "pylint"] + args + [path]
|
||||||
57 | pylint_call_tuple = (sys.executable, "-m", "pylint") + args + (path, path2)
|
57 | pylint_call_tuple = (sys.executable, "-m", "pylint") + args + (path, path2)
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ RUF005
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ RUF005
|
||||||
58 | b = a + [2, 3] + [4]
|
58 | b = a + [2, 3] + [4]
|
||||||
|
|
|
|
||||||
= help: Replace with `(sys.executable, "-m", "pylint", *args, path, path2)`
|
= help: Replace with iterable unpacking
|
||||||
|
|
||||||
ℹ Suggested fix
|
ℹ Suggested fix
|
||||||
54 54 | ]
|
54 54 | ]
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue