Repository: astral-sh/ruff
File: crates/ruff_linter/src/rules/ruff/rules/unnecessary_regular_expression.rs (Rust)

Code before:

    // For now, restrict this rule to string literals and variables that can be resolved to literals
    let Some(literal) = resolve_literal(re_func.pattern, semantic) else {
        return;
    };

    // For now, reject any regex metacharacters. Compare to the complete list
    // from https://docs.python.org/3/howto/regex.html#matching-characters
    let has_metacharacters = match &literal {
        Literal::Str(str_lit) => str_lit.value.to_str().contains(METACHARACTERS),
        Literal::Bytes(bytes_lit) => bytes_lit
            .value
            .iter()
            .any(|part| part.iter().any(|&b| METACHARACTERS.contains(&(b as char)))),
    };

    if has_metacharacters {
        return;
    }

    // `str.split("")` raises `ValueError: empty separator` while `re.split("", s)` succeeds,
    // so skip the diagnostic for `re.split` with an empty pattern.
    if matches!(re_func.kind, ReFuncKind::Split) {
        let is_empty = match &literal {
            Literal::Str(str_lit) => str_lit.value.to_str().is_empty(),
            Literal::Bytes(bytes_lit) => bytes_lit.value.iter().all(|part| part.is_empty()),
        };
        if is_empty {
            return;
        }
    }

    // Now we know the pattern is a string literal with no metacharacters, so
    // we can proceed with the str method replacement.
    let new_expr = re_func.replacement();

    let repl = new_expr.map(|expr| checker.generator().expr(&expr));
    let mut diagnostic = checker.report_diagnostic(
        UnnecessaryRegularExpression {
            replacement: repl.clone(),
        },
        re_func.range,
    );

    if let Some(repl) = repl {
        diagnostic.set_fix(Fix::applicable_edit(
            Edit::range_replacement(repl, re_func.range),
            if checker.comment_ranges().intersects(re_func.range) {
                Applicability::Unsafe
            } else {
                Applicability::Safe

Review comment (suggestion):
I think both of these types have `is_empty` methods:


```suggestion
            Literal::Str(str_lit) => str_lit.value.is_empty(),
            Literal::Bytes(bytes_lit) => bytes_lit.value.is_empty(),
```

This might be a nice method on `Literal`, so that we can just write:

```rust
if matches!(re_func.kind, ReFuncKind::Split) && literal.is_empty() {
	return;
}
```

Code after:

    // For now, restrict this rule to string literals and variables that can be resolved to literals
    let Some(literal) = resolve_literal(re_func.pattern, semantic) else {
        return;
    };

    // For now, reject any regex metacharacters. Compare to the complete list
    // from https://docs.python.org/3/howto/regex.html#matching-characters
    let has_metacharacters = match &literal {
        Literal::Str(str_lit) => str_lit.value.to_str().contains(METACHARACTERS),
        Literal::Bytes(bytes_lit) => bytes_lit
            .value
            .iter()
            .any(|part| part.iter().any(|&b| METACHARACTERS.contains(&(b as char)))),
    };

    if has_metacharacters {
        return;
    }

    // `str.split("")` raises `ValueError: empty separator` while `re.split("", s)` succeeds,
    // so skip the diagnostic for `re.split` with an empty pattern.
    if matches!(re_func.kind, ReFuncKind::Split) && literal.is_empty() {
        return;
    }

    // Now we know the pattern is a string literal with no metacharacters, so
    // we can proceed with the str method replacement.
    let new_expr = re_func.replacement();

    let repl = new_expr.map(|expr| checker.generator().expr(&expr));
    let mut diagnostic = checker.report_diagnostic(
        UnnecessaryRegularExpression {
            replacement: repl.clone(),
        },
        re_func.range,
    );

    if let Some(repl) = repl {
        diagnostic.set_fix(Fix::applicable_edit(
            Edit::range_replacement(repl, re_func.range),
            if checker.comment_ranges().intersects(re_func.range) {
                Applicability::Unsafe
            } else {
                Applicability::Safe
            },
        ));
    }
}

/// The `re` functions supported by this rule.