Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/ide-assists/src/utils.rs')
-rw-r--r--crates/ide-assists/src/utils.rs78
1 files changed, 74 insertions, 4 deletions
diff --git a/crates/ide-assists/src/utils.rs b/crates/ide-assists/src/utils.rs
index c1332d99bf..39686f065a 100644
--- a/crates/ide-assists/src/utils.rs
+++ b/crates/ide-assists/src/utils.rs
@@ -17,7 +17,9 @@ use syntax::{
self,
edit::{AstNodeEdit, IndentLevel},
edit_in_place::{AttrsOwnerEdit, Indent, Removable},
- make, HasArgList, HasAttrs, HasGenericParams, HasName, HasTypeBounds, Whitespace,
+ make,
+ syntax_factory::SyntaxFactory,
+ HasArgList, HasAttrs, HasGenericParams, HasName, HasTypeBounds, Whitespace,
},
ted, AstNode, AstToken, Direction, Edition, NodeOrToken, SourceFile,
SyntaxKind::*,
@@ -245,11 +247,79 @@ pub(crate) fn vis_offset(node: &SyntaxNode) -> TextSize {
.unwrap_or_else(|| node.text_range().start())
}
-pub(crate) fn invert_boolean_expression(expr: ast::Expr) -> ast::Expr {
- invert_special_case(&expr).unwrap_or_else(|| make::expr_prefix(T![!], expr).into())
+pub(crate) fn invert_boolean_expression(make: &SyntaxFactory, expr: ast::Expr) -> ast::Expr {
+ invert_special_case(make, &expr).unwrap_or_else(|| make.expr_prefix(T![!], expr).into())
}
-fn invert_special_case(expr: &ast::Expr) -> Option<ast::Expr> {
+// FIXME: Migrate usages of this function to the above function and remove this.
+pub(crate) fn invert_boolean_expression_legacy(expr: ast::Expr) -> ast::Expr {
+ invert_special_case_legacy(&expr).unwrap_or_else(|| make::expr_prefix(T![!], expr).into())
+}
+
+fn invert_special_case(make: &SyntaxFactory, expr: &ast::Expr) -> Option<ast::Expr> {
+ match expr {
+ ast::Expr::BinExpr(bin) => {
+ let op_kind = bin.op_kind()?;
+ let rev_kind = match op_kind {
+ ast::BinaryOp::CmpOp(ast::CmpOp::Eq { negated }) => {
+ ast::BinaryOp::CmpOp(ast::CmpOp::Eq { negated: !negated })
+ }
+ ast::BinaryOp::CmpOp(ast::CmpOp::Ord { ordering: ast::Ordering::Less, strict }) => {
+ ast::BinaryOp::CmpOp(ast::CmpOp::Ord {
+ ordering: ast::Ordering::Greater,
+ strict: !strict,
+ })
+ }
+ ast::BinaryOp::CmpOp(ast::CmpOp::Ord {
+ ordering: ast::Ordering::Greater,
+ strict,
+ }) => ast::BinaryOp::CmpOp(ast::CmpOp::Ord {
+ ordering: ast::Ordering::Less,
+ strict: !strict,
+ }),
+ // Parenthesize other expressions before prefixing `!`
+ _ => {
+ return Some(
+ make.expr_prefix(T![!], make.expr_paren(expr.clone()).into()).into(),
+ );
+ }
+ };
+
+ Some(make.expr_bin(bin.lhs()?, rev_kind, bin.rhs()?).into())
+ }
+ ast::Expr::MethodCallExpr(mce) => {
+ let receiver = mce.receiver()?;
+ let method = mce.name_ref()?;
+ let arg_list = mce.arg_list()?;
+
+ let method = match method.text().as_str() {
+ "is_some" => "is_none",
+ "is_none" => "is_some",
+ "is_ok" => "is_err",
+ "is_err" => "is_ok",
+ _ => return None,
+ };
+
+ Some(make.expr_method_call(receiver, make.name_ref(method), arg_list).into())
+ }
+ ast::Expr::PrefixExpr(pe) if pe.op_kind()? == ast::UnaryOp::Not => match pe.expr()? {
+ ast::Expr::ParenExpr(parexpr) => {
+ parexpr.expr().map(|e| e.clone_subtree().clone_for_update())
+ }
+ _ => pe.expr().map(|e| e.clone_subtree().clone_for_update()),
+ },
+ ast::Expr::Literal(lit) => match lit.kind() {
+ ast::LiteralKind::Bool(b) => match b {
+ true => Some(ast::Expr::Literal(make.expr_literal("false"))),
+ false => Some(ast::Expr::Literal(make.expr_literal("true"))),
+ },
+ _ => None,
+ },
+ _ => None,
+ }
+}
+
+fn invert_special_case_legacy(expr: &ast::Expr) -> Option<ast::Expr> {
match expr {
ast::Expr::BinExpr(bin) => {
let bin = bin.clone_for_update();