From 694f7a7e9f90cc435afcaade23b5908728d17ed2 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Wed, 24 Feb 2021 11:42:32 +0100 Subject: Add tests for apply_demorgan --- crates/ide_assists/src/handlers/apply_demorgan.rs | 67 +++++++++++++++++++++++ crates/ide_assists/src/utils.rs | 27 ++++----- crates/syntax/src/ast/make.rs | 7 ++- 3 files changed, 83 insertions(+), 18 deletions(-) diff --git a/crates/ide_assists/src/handlers/apply_demorgan.rs b/crates/ide_assists/src/handlers/apply_demorgan.rs index 3cd6699c3..6997ea048 100644 --- a/crates/ide_assists/src/handlers/apply_demorgan.rs +++ b/crates/ide_assists/src/handlers/apply_demorgan.rs @@ -61,10 +61,77 @@ fn opposite_logic_op(kind: ast::BinOp) -> Option<&'static str> { #[cfg(test)] mod tests { + use ide_db::helpers::FamousDefs; + use super::*; use crate::tests::{check_assist, check_assist_not_applicable}; + const ORDABLE_FIXTURE: &'static str = r" +//- /lib.rs deps:core crate:ordable +struct NonOrderable; +struct Orderable; +impl core::cmp::Ord for Orderable {} +"; + + fn check(ra_fixture_before: &str, ra_fixture_after: &str) { + let before = &format!( + "//- /main.rs crate:main deps:core,ordable\n{}\n{}{}", + ra_fixture_before, + FamousDefs::FIXTURE, + ORDABLE_FIXTURE + ); + check_assist(apply_demorgan, before, &format!("{}\n", ra_fixture_after)); + } + + #[test] + fn demorgan_handles_leq() { + check( + r"use ordable::Orderable; +fn f() { + Orderable < Orderable &&$0 Orderable <= Orderable +}", + r"use ordable::Orderable; +fn f() { + !(Orderable >= Orderable || Orderable > Orderable) +}", + ); + check( + r"use ordable::NonOrderable; +fn f() { + NonOrderable < NonOrderable &&$0 NonOrderable <= NonOrderable +}", + r"use ordable::NonOrderable; +fn f() { + !(!(NonOrderable < NonOrderable) || !(NonOrderable <= NonOrderable)) +}", + ); + } + + #[test] + fn demorgan_handles_geq() { + check( + r"use ordable::Orderable; +fn f() { + Orderable > Orderable &&$0 Orderable >= Orderable +}", + r"use ordable::Orderable; +fn f() { + !(Orderable <= Orderable || Orderable < Orderable) +}", + ); + check( + r"use ordable::NonOrderable; +fn f() { + Orderable > Orderable &&$0 Orderable >= Orderable +}", + r"use ordable::NonOrderable; +fn f() { + !(!(Orderable > Orderable) || !(Orderable >= Orderable)) +}", + ); + } + #[test] fn demorgan_turns_and_into_or() { check_assist(apply_demorgan, "fn f() { !x &&$0 !x }", "fn f() { !(x || x) }") diff --git a/crates/ide_assists/src/utils.rs b/crates/ide_assists/src/utils.rs index 38ed74673..276792bc1 100644 --- a/crates/ide_assists/src/utils.rs +++ b/crates/ide_assists/src/utils.rs @@ -267,24 +267,19 @@ fn invert_special_case(sema: &Semantics, expr: &ast::Expr) -> Opti } fn bin_impls_ord(sema: &Semantics, bin: &ast::BinExpr) -> bool { - if let (Some(lhs), Some(rhs)) = (bin.lhs(), bin.rhs()) { - return sema.type_of_expr(&lhs) == sema.type_of_expr(&rhs) - && impls_ord(sema, &lhs) - && impls_ord(sema, &rhs); - } - false -} - -fn impls_ord(sema: &Semantics, expr: &ast::Expr) -> bool { - let krate = sema.scope(expr.syntax()).module().map(|it| it.krate()); - let famous_defs = FamousDefs(&sema, krate); - - if let Some(ty) = sema.type_of_expr(expr) { - if let Some(ord_trait) = famous_defs.core_cmp_Ord() { - return ty.autoderef(sema.db).any(|ty| ty.impls_trait(sema.db, ord_trait, &[])); + match ( + bin.lhs().and_then(|lhs| sema.type_of_expr(&lhs)), + bin.rhs().and_then(|rhs| sema.type_of_expr(&rhs)), + ) { + (Some(lhs_ty), Some(rhs_ty)) if lhs_ty == rhs_ty => { + let krate = sema.scope(bin.syntax()).module().map(|it| it.krate()); + let ord_trait = FamousDefs(sema, krate).core_cmp_Ord(); + ord_trait.map_or(false, |ord_trait| { + lhs_ty.autoderef(sema.db).any(|ty| ty.impls_trait(sema.db, ord_trait, &[])) + }) } + _ => false, } - false } pub(crate) fn next_prev() -> impl Iterator { diff --git a/crates/syntax/src/ast/make.rs b/crates/syntax/src/ast/make.rs index 5eee33545..b6c5de658 100644 --- a/crates/syntax/src/ast/make.rs +++ b/crates/syntax/src/ast/make.rs @@ -527,8 +527,11 @@ pub mod tokens { use crate::{ast, AstNode, Parse, SourceFile, SyntaxKind::*, SyntaxToken}; - pub(super) static SOURCE_FILE: Lazy> = - Lazy::new(|| SourceFile::parse("const C: <()>::Item = (1 != 1, 2 == 2, !true, *p)\n;\n\n")); + pub(super) static SOURCE_FILE: Lazy> = Lazy::new(|| { + SourceFile::parse( + "const C: <()>::Item = (1 != 1, 2 == 2, 3 < 3, 4 <= 4, 5 > 5, 6 >= 6, !true, *p)\n;\n\n", + ) + }); pub fn single_space() -> SyntaxToken { SOURCE_FILE -- cgit v1.2.3