diff --git a/crates/squawk_ide/src/code_actions/mod.rs b/crates/squawk_ide/src/code_actions/mod.rs index 15820291..13495793 100644 --- a/crates/squawk_ide/src/code_actions/mod.rs +++ b/crates/squawk_ide/src/code_actions/mod.rs @@ -27,6 +27,7 @@ mod rewrite_is_normalized_as_function_call; mod rewrite_leading_from; mod rewrite_normalize_as_function_call; mod rewrite_not_equals_operator; +mod rewrite_null_predicate; mod rewrite_overlaps_as_function_call; mod rewrite_overlay_as_function_call; mod rewrite_pattern_matching_as_operators; @@ -72,6 +73,7 @@ use rewrite_is_normalized_as_function_call::rewrite_is_normalized_as_function_ca use rewrite_leading_from::rewrite_leading_from; use rewrite_normalize_as_function_call::rewrite_normalize_as_function_call; use rewrite_not_equals_operator::rewrite_not_equals_operator; +use rewrite_null_predicate::rewrite_null_predicate; use rewrite_overlaps_as_function_call::rewrite_overlaps_as_function_call; use rewrite_overlay_as_function_call::rewrite_overlay_as_function_call; use rewrite_pattern_matching_as_operators::rewrite_pattern_matching_as_operators; @@ -127,6 +129,7 @@ pub fn code_actions(db: &dyn Db, position: InFile) -> Option, + actions: &mut Vec, +) -> Option<()> { + let token = token_from_offset(db, position)?; + let postfix_expr = token.parent_ancestors().find_map(ast::PostfixExpr::cast)?; + + let (op_token, replacement, title) = match postfix_expr.op()? { + PostfixOp::IsNull(token) => (token, "is null", "Rewrite as `IS NULL`"), + PostfixOp::NotNull(token) => (token, "is not null", "Rewrite as `IS NOT NULL`"), + _ => return None, + }; + + actions.push(CodeAction { + title: title.to_owned(), + edits: vec![Edit::replace(op_token.text_range(), replacement.to_owned())], + kind: ActionKind::RefactorRewrite, + }); + + Some(()) +} + +#[cfg(test)] +mod test { + use insta::assert_snapshot; + + use crate::code_actions::test_utils::{apply_code_action, code_action_not_applicable}; + + use super::rewrite_null_predicate; + + #[test] + fn rewrites_isnull() { + assert_snapshot!( + apply_code_action(rewrite_null_predicate, "select x is$0null from t;"), + @"select x is null from t;" + ); + } + + #[test] + fn rewrites_notnull() { + assert_snapshot!( + apply_code_action(rewrite_null_predicate, "select x not$0null from t;"), + @"select x is not null from t;" + ); + } + + #[test] + fn applies_when_cursor_is_on_the_value() { + assert_snapshot!( + apply_code_action(rewrite_null_predicate, "select val$0ue isnull from t;"), + @"select value is null from t;" + ); + } + + #[test] + fn is_not_applicable_outside_null_predicate() { + assert!(code_action_not_applicable( + rewrite_null_predicate, + "select val$0ue from t;" + )); + } +}