Skip to content

Commit

Permalink
[refurb] Implement slice-to-remove-prefix-or-suffix (FURB188) (#1…
Browse files Browse the repository at this point in the history
  • Loading branch information
dylwil3 committed Sep 9, 2024
1 parent a98dbce commit b04948f
Show file tree
Hide file tree
Showing 9 changed files with 816 additions and 0 deletions.
154 changes: 154 additions & 0 deletions crates/ruff_linter/resources/test/fixtures/refurb/FURB188.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
# Test suite from Refurb
# See https://github.com/dosisod/refurb/blob/db02242b142285e615a664a8d3324470bb711306/test/data/err_188.py

# these should match

def remove_extension_via_slice(filename: str) -> str:
if filename.endswith(".txt"):
filename = filename[:-4]

return filename


def remove_extension_via_slice_len(filename: str, extension: str) -> str:
if filename.endswith(extension):
filename = filename[:-len(extension)]

return filename


def remove_extension_via_ternary(filename: str) -> str:
return filename[:-4] if filename.endswith(".txt") else filename


def remove_extension_via_ternary_with_len(filename: str, extension: str) -> str:
return filename[:-len(extension)] if filename.endswith(extension) else filename


def remove_prefix(filename: str) -> str:
return filename[4:] if filename.startswith("abc-") else filename


def remove_prefix_via_len(filename: str, prefix: str) -> str:
return filename[len(prefix):] if filename.startswith(prefix) else filename


# these should not

def remove_extension_with_mismatched_len(filename: str) -> str:
if filename.endswith(".txt"):
filename = filename[:3]

return filename


def remove_extension_assign_to_different_var(filename: str) -> str:
if filename.endswith(".txt"):
other_var = filename[:-4]

return filename


def remove_extension_with_multiple_stmts(filename: str) -> str:
if filename.endswith(".txt"):
print("do some work")

filename = filename[:-4]

if filename.endswith(".txt"):
filename = filename[:-4]

print("do some work")

return filename


def remove_extension_from_unrelated_var(filename: str) -> str:
xyz = "abc.txt"

if filename.endswith(".txt"):
filename = xyz[:-4]

return filename


def remove_extension_in_elif(filename: str) -> str:
if filename:
pass

elif filename.endswith(".txt"):
filename = filename[:-4]

return filename


def remove_extension_in_multiple_elif(filename: str) -> str:
if filename:
pass

elif filename:
pass

elif filename.endswith(".txt"):
filename = filename[:-4]

return filename


def remove_extension_in_if_with_else(filename: str) -> str:
if filename.endswith(".txt"):
filename = filename[:-4]

else:
pass

return filename


def remove_extension_ternary_name_mismatch(filename: str):
xyz = ""

_ = xyz[:-4] if filename.endswith(".txt") else filename
_ = filename[:-4] if xyz.endswith(".txt") else filename
_ = filename[:-4] if filename.endswith(".txt") else xyz


def remove_extension_slice_amount_mismatch(filename: str) -> None:
extension = ".txt"

_ = filename[:-1] if filename.endswith(".txt") else filename
_ = filename[:-1] if filename.endswith(extension) else filename
_ = filename[:-len("")] if filename.endswith(extension) else filename


def remove_prefix_size_mismatch(filename: str) -> str:
return filename[3:] if filename.startswith("abc-") else filename


def remove_prefix_name_mismatch(filename: str) -> None:
xyz = ""

_ = xyz[4:] if filename.startswith("abc-") else filename
_ = filename[4:] if xyz.startswith("abc-") else filename
_ = filename[4:] if filename.startswith("abc-") else xyz

# ---- End of refurb test suite ---- #

# ---- Begin ruff specific test suite --- #

# these should be linted

def remove_suffix_multiple_attribute_expr() -> None:
import foo.bar

SUFFIX = "suffix"

x = foo.bar.baz[:-len(SUFFIX)] if foo.bar.baz.endswith(SUFFIX) else foo.bar.baz

def remove_prefix_comparable_literal_expr() -> None:
return ("abc" "def")[3:] if ("abc" "def").startswith("abc") else "abc" "def"

def shadow_builtins(filename: str, extension: str) -> None:
from builtins import len as builtins_len

return filename[:-builtins_len(extension)] if filename.endswith(extension) else filename
3 changes: 3 additions & 0 deletions crates/ruff_linter/src/checkers/ast/analyze/expression.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1407,6 +1407,9 @@ pub(crate) fn expression(expr: &Expr, checker: &mut Checker) {
if checker.enabled(Rule::UselessIfElse) {
ruff::rules::useless_if_else(checker, if_exp);
}
if checker.enabled(Rule::SliceToRemovePrefixOrSuffix) {
refurb::rules::slice_to_remove_affix_expr(checker, if_exp);
}
}
Expr::ListComp(
comp @ ast::ExprListComp {
Expand Down
3 changes: 3 additions & 0 deletions crates/ruff_linter/src/checkers/ast/analyze/statement.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1178,6 +1178,9 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) {
if checker.enabled(Rule::CheckAndRemoveFromSet) {
refurb::rules::check_and_remove_from_set(checker, if_);
}
if checker.enabled(Rule::SliceToRemovePrefixOrSuffix) {
refurb::rules::slice_to_remove_affix_stmt(checker, if_);
}
if checker.enabled(Rule::TooManyBooleanExpressions) {
pylint::rules::too_many_boolean_expressions(checker, if_);
}
Expand Down
1 change: 1 addition & 0 deletions crates/ruff_linter/src/codes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1067,6 +1067,7 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<(RuleGroup, Rule)> {
(Refurb, "180") => (RuleGroup::Preview, rules::refurb::rules::MetaClassABCMeta),
(Refurb, "181") => (RuleGroup::Stable, rules::refurb::rules::HashlibDigestHex),
(Refurb, "187") => (RuleGroup::Stable, rules::refurb::rules::ListReverseCopy),
(Refurb, "188") => (RuleGroup::Preview, rules::refurb::rules::SliceToRemovePrefixOrSuffix),
(Refurb, "192") => (RuleGroup::Preview, rules::refurb::rules::SortedMinMax),

// flake8-logging
Expand Down
1 change: 1 addition & 0 deletions crates/ruff_linter/src/rules/refurb/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ mod tests {
#[test_case(Rule::WriteWholeFile, Path::new("FURB103.py"))]
#[test_case(Rule::FStringNumberFormat, Path::new("FURB116.py"))]
#[test_case(Rule::SortedMinMax, Path::new("FURB192.py"))]
#[test_case(Rule::SliceToRemovePrefixOrSuffix, Path::new("FURB188.py"))]
fn rules(rule_code: Rule, path: &Path) -> Result<()> {
let snapshot = format!("{}_{}", rule_code.noqa_code(), path.to_string_lossy());
let diagnostics = test_path(
Expand Down
2 changes: 2 additions & 0 deletions crates/ruff_linter/src/rules/refurb/rules/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ pub(crate) use repeated_append::*;
pub(crate) use repeated_global::*;
pub(crate) use single_item_membership_test::*;
pub(crate) use slice_copy::*;
pub(crate) use slice_to_remove_prefix_or_suffix::*;
pub(crate) use sorted_min_max::*;
pub(crate) use type_none_comparison::*;
pub(crate) use unnecessary_enumerate::*;
Expand Down Expand Up @@ -55,6 +56,7 @@ mod repeated_append;
mod repeated_global;
mod single_item_membership_test;
mod slice_copy;
mod slice_to_remove_prefix_or_suffix;
mod sorted_min_max;
mod type_none_comparison;
mod unnecessary_enumerate;
Expand Down
Loading

0 comments on commit b04948f

Please sign in to comment.