From 1d129a7172bbe502182be6cc3b50b3250cb6f3a9 Mon Sep 17 00:00:00 2001 From: dragfire Date: Sun, 23 Aug 2020 14:30:07 -0600 Subject: Invert if should be smart about is_some, is_none, is_ok, is_err --- crates/assists/src/handlers/invert_if.rs | 18 ++++++++++++++++++ crates/assists/src/utils.rs | 21 ++++++++++++++++++++- crates/syntax/src/ast/make.rs | 8 +++++++- 3 files changed, 45 insertions(+), 2 deletions(-) diff --git a/crates/assists/src/handlers/invert_if.rs b/crates/assists/src/handlers/invert_if.rs index f0e047538..294256297 100644 --- a/crates/assists/src/handlers/invert_if.rs +++ b/crates/assists/src/handlers/invert_if.rs @@ -106,4 +106,22 @@ mod tests { "fn f() { i<|>f let Some(_) = Some(1) { 1 } else { 0 } }", ) } + + #[test] + fn invert_if_option_case() { + check_assist( + invert_if, + "fn f() { if<|> doc_style.is_some() { Class::DocComment } else { Class::Comment } }", + "fn f() { if doc_style.is_none() { Class::Comment } else { Class::DocComment } }", + ) + } + + #[test] + fn invert_if_result_case() { + check_assist( + invert_if, + "fn f() { i<|>f doc_style.is_err() { Class::Err } else { Class::Ok } }", + "fn f() { if doc_style.is_ok() { Class::Ok } else { Class::Err } }", + ) + } } diff --git a/crates/assists/src/utils.rs b/crates/assists/src/utils.rs index d071d6502..e15c982e7 100644 --- a/crates/assists/src/utils.rs +++ b/crates/assists/src/utils.rs @@ -11,7 +11,7 @@ use syntax::{ ast::{self, make, NameOwner}, AstNode, Direction, SyntaxKind::*, - SyntaxNode, TextSize, T, + SyntaxNode, SyntaxText, TextSize, T, }; use crate::assist_config::SnippetCap; @@ -179,6 +179,25 @@ fn invert_special_case(expr: &ast::Expr) -> Option { ast::BinOp::EqualityTest => bin.replace_op(T![!=]).map(|it| it.into()), _ => None, }, + ast::Expr::MethodCallExpr(mce) => { + const IS_SOME_TEXT: &str = "is_some"; + const IS_NONE_TEXT: &str = "is_none"; + const IS_OK_TEXT: &str = "is_ok"; + const IS_ERR_TEXT: &str = "is_err"; + + let name = mce.name_ref()?; + let name_text = name.text(); + + let caller = || -> Option { Some(mce.receiver()?.syntax().text()) }; + + match name_text { + x if x == IS_SOME_TEXT => make::expr_method_call(IS_NONE_TEXT, caller), + x if x == IS_NONE_TEXT => make::expr_method_call(IS_SOME_TEXT, caller), + x if x == IS_OK_TEXT => make::expr_method_call(IS_ERR_TEXT, caller), + x if x == IS_ERR_TEXT => make::expr_method_call(IS_OK_TEXT, caller), + _ => None, + } + } ast::Expr::PrefixExpr(pe) if pe.op_kind()? == ast::PrefixOp::Not => pe.expr(), // FIXME: // ast::Expr::Literal(true | false ) diff --git a/crates/syntax/src/ast/make.rs b/crates/syntax/src/ast/make.rs index d20c085aa..7958721e2 100644 --- a/crates/syntax/src/ast/make.rs +++ b/crates/syntax/src/ast/make.rs @@ -7,7 +7,7 @@ use itertools::Itertools; use stdx::format_to; -use crate::{ast, AstNode, SourceFile, SyntaxKind, SyntaxNode, SyntaxToken}; +use crate::{ast, AstNode, SourceFile, SyntaxKind, SyntaxNode, SyntaxText, SyntaxToken}; pub fn name(text: &str) -> ast::Name { ast_from_text(&format!("mod {};", text)) @@ -137,6 +137,12 @@ pub fn expr_prefix(op: SyntaxKind, expr: ast::Expr) -> ast::Expr { pub fn expr_call(f: ast::Expr, arg_list: ast::ArgList) -> ast::Expr { expr_from_text(&format!("{}{}", f, arg_list)) } +pub fn expr_method_call(text: &str, caller: F) -> Option +where + F: FnOnce() -> Option, +{ + try_expr_from_text(&format!("{}.{}()", caller()?, text)) +} fn expr_from_text(text: &str) -> ast::Expr { ast_from_text(&format!("const C: () = {};", text)) } -- cgit v1.2.3