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

Code before:
}

#[derive(Clone, Debug, Eq, PartialEq)]
pub(crate) enum FunctionSignatureChange {
    /// Carries a message describing the function signature change.
    Message(&'static str),
}

pub(crate) fn is_guarded_by_try_except(
    expr: &Expr,
    module: &str,
    name: &str,
    semantic: &SemanticModel,
) -> bool {
    match expr {
        Expr::Attribute(_) => {
            if !semantic.in_exception_handler() {
                return false;
            }
            let Some(try_node) = semantic
                .current_statements()
                .find_map(|stmt| stmt.as_try_stmt())
            else {
                return false;
            };
            let suspended_exceptions = Exceptions::from_try_stmt(try_node, semantic);
            if !suspended_exceptions.contains(Exceptions::ATTRIBUTE_ERROR) {
                return false;
            }
            try_block_contains_undeprecated_attribute(try_node, module, name, semantic)
        }
        Expr::Name(ExprName { id, .. }) => {
            let Some(binding_id) = semantic.lookup_symbol(id.as_str()) else {
                return false;
            };
            let binding = semantic.binding(binding_id);
            if !binding.is_external() {
                return false;
            }
            if !binding.in_exception_handler() {
                return false;
            }
            let Some(try_node) = binding.source.and_then(|import_id| {
                semantic
                    .statements(import_id)
                    .find_map(|stmt| stmt.as_try_stmt())
            }) else {
                return false;
            };
            let suspended_exceptions = Exceptions::from_try_stmt(try_node, semantic);
            if !suspended_exceptions

Review comment (bug):
The original definition in `function_signature_change_in_3.rs` becomes redundant as these enum items only encapsulate a message. Therefore, combine these into a single `Message` item, and move it to `helpers.rs`. This enum will be dedicated used for AIR303, or function signature change in future version of Airflow.

```rust
#[derive(Clone, Debug, Eq, PartialEq)]
pub(crate) enum FunctionSignatureChangeType {
    /// Function signature changed to only accept keyword arguments.
    KeywordOnly { message: &'static str },
    /// Function signature changed to not accept certain positional arguments.
    PositionalArgumentChange { message: &'static str },
}
```

Code after:
        suggest_fix: bool,
    },
}

#[derive(Clone, Debug, Eq, PartialEq)]
pub(crate) enum ProviderReplacement {
    Rename {
        module: &'static str,
        name: &'static str,
        provider: &'static str,
        version: &'static str,
    },
    SourceModuleMovedToProvider {
        module: &'static str,
        name: String,
        provider: &'static str,
        version: &'static str,
    },
}

#[derive(Clone, Debug, Eq, PartialEq)]
pub(crate) enum FunctionSignatureChange {
    /// Carries a message describing the function signature change.
    Message(&'static str),
}

pub(crate) fn is_guarded_by_try_except(
    expr: &Expr,
    module: &str,
    name: &str,
    semantic: &SemanticModel,
) -> bool {
    match expr {
        Expr::Attribute(_) => {
            if !semantic.in_exception_handler() {
                return false;
            }
            let Some(try_node) = semantic
                .current_statements()
                .find_map(|stmt| stmt.as_try_stmt())
            else {
                return false;
            };
            let suspended_exceptions = Exceptions::from_try_stmt(try_node, semantic);
            if !suspended_exceptions.contains(Exceptions::ATTRIBUTE_ERROR) {
                return false;
            }
            try_block_contains_undeprecated_attribute(try_node, module, name, semantic)
        }
        Expr::Name(ExprName { id, .. }) => {
            let Some(binding_id) = semantic.lookup_symbol(id.as_str()) else {