aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_assists/src/handlers
diff options
context:
space:
mode:
authorAleksey Kladov <[email protected]>2020-04-29 13:49:54 +0100
committerAleksey Kladov <[email protected]>2020-04-29 13:51:44 +0100
commitb4dd4752570d5f1ba24f7ffda69be4b1c935cd04 (patch)
treed922c9af05c682086d7a3f6f93c0fed51327ee0d /crates/ra_assists/src/handlers
parentc3dfeba165e4d13821bba34d21cdc5242ea2fa71 (diff)
More principled approach for finding From trait
Diffstat (limited to 'crates/ra_assists/src/handlers')
-rw-r--r--crates/ra_assists/src/handlers/add_from_impl_for_enum.rs70
1 files changed, 34 insertions, 36 deletions
diff --git a/crates/ra_assists/src/handlers/add_from_impl_for_enum.rs b/crates/ra_assists/src/handlers/add_from_impl_for_enum.rs
index 03806724a..49deb6701 100644
--- a/crates/ra_assists/src/handlers/add_from_impl_for_enum.rs
+++ b/crates/ra_assists/src/handlers/add_from_impl_for_enum.rs
@@ -1,11 +1,12 @@
1use ra_ide_db::RootDatabase;
1use ra_syntax::{ 2use ra_syntax::{
2 ast::{self, AstNode, NameOwner}, 3 ast::{self, AstNode, NameOwner},
3 TextSize, 4 TextSize,
4}; 5};
5use stdx::format_to; 6use stdx::format_to;
6 7
7use crate::{Assist, AssistCtx, AssistId}; 8use crate::{utils::FamousDefs, Assist, AssistCtx, AssistId};
8use ra_ide_db::RootDatabase; 9use test_utils::tested_by;
9 10
10// Assist add_from_impl_for_enum 11// Assist add_from_impl_for_enum
11// 12//
@@ -41,7 +42,8 @@ pub(crate) fn add_from_impl_for_enum(ctx: AssistCtx) -> Option<Assist> {
41 _ => return None, 42 _ => return None,
42 }; 43 };
43 44
44 if already_has_from_impl(ctx.sema, &variant) { 45 if existing_from_impl(ctx.sema, &variant).is_some() {
46 tested_by!(test_add_from_impl_already_exists);
45 return None; 47 return None;
46 } 48 }
47 49
@@ -70,41 +72,33 @@ impl From<{0}> for {1} {{
70 ) 72 )
71} 73}
72 74
73fn already_has_from_impl( 75fn existing_from_impl(
74 sema: &'_ hir::Semantics<'_, RootDatabase>, 76 sema: &'_ hir::Semantics<'_, RootDatabase>,
75 variant: &ast::EnumVariant, 77 variant: &ast::EnumVariant,
76) -> bool { 78) -> Option<()> {
77 let scope = sema.scope(&variant.syntax()); 79 let variant = sema.to_def(variant)?;
80 let enum_ = variant.parent_enum(sema.db);
81 let krate = enum_.module(sema.db).krate();
78 82
79 let from_path = ast::make::path_from_text("From"); 83 let from_trait = FamousDefs(sema, krate).core_convert_From()?;
80 let from_hir_path = match hir::Path::from_ast(from_path) {
81 Some(p) => p,
82 None => return false,
83 };
84 let from_trait = match scope.resolve_hir_path(&from_hir_path) {
85 Some(hir::PathResolution::Def(hir::ModuleDef::Trait(t))) => t,
86 _ => return false,
87 };
88 84
89 let e: hir::Enum = match sema.to_def(&variant.parent_enum()) { 85 let enum_type = enum_.ty(sema.db);
90 Some(e) => e,
91 None => return false,
92 };
93 let e_ty = e.ty(sema.db);
94 86
95 let hir_enum_var: hir::EnumVariant = match sema.to_def(variant) { 87 let wrapped_type = variant.fields(sema.db).get(0)?.signature_ty(sema.db);
96 Some(ev) => ev,
97 None => return false,
98 };
99 let var_ty = hir_enum_var.fields(sema.db)[0].signature_ty(sema.db);
100 88
101 e_ty.impls_trait(sema.db, from_trait, &[var_ty]) 89 if enum_type.impls_trait(sema.db, from_trait, &[wrapped_type]) {
90 Some(())
91 } else {
92 None
93 }
102} 94}
103 95
104#[cfg(test)] 96#[cfg(test)]
105mod tests { 97mod tests {
106 use super::*; 98 use super::*;
99
107 use crate::helpers::{check_assist, check_assist_not_applicable}; 100 use crate::helpers::{check_assist, check_assist_not_applicable};
101 use test_utils::covers;
108 102
109 #[test] 103 #[test]
110 fn test_add_from_impl_for_enum() { 104 fn test_add_from_impl_for_enum() {
@@ -136,36 +130,40 @@ mod tests {
136 ); 130 );
137 } 131 }
138 132
133 fn check_not_applicable(ra_fixture: &str) {
134 let fixture =
135 format!("//- main.rs crate:main deps:core\n{}\n{}", ra_fixture, FamousDefs::FIXTURE);
136 check_assist_not_applicable(add_from_impl_for_enum, &fixture)
137 }
138
139 #[test] 139 #[test]
140 fn test_add_from_impl_no_element() { 140 fn test_add_from_impl_no_element() {
141 check_assist_not_applicable(add_from_impl_for_enum, "enum A { <|>One }"); 141 check_not_applicable("enum A { <|>One }");
142 } 142 }
143 143
144 #[test] 144 #[test]
145 fn test_add_from_impl_more_than_one_element_in_tuple() { 145 fn test_add_from_impl_more_than_one_element_in_tuple() {
146 check_assist_not_applicable(add_from_impl_for_enum, "enum A { <|>One(u32, String) }"); 146 check_not_applicable("enum A { <|>One(u32, String) }");
147 } 147 }
148 148
149 #[test] 149 #[test]
150 fn test_add_from_impl_struct_variant() { 150 fn test_add_from_impl_struct_variant() {
151 check_assist_not_applicable(add_from_impl_for_enum, "enum A { <|>One { x: u32 } }"); 151 check_not_applicable("enum A { <|>One { x: u32 } }");
152 } 152 }
153 153
154 #[test] 154 #[test]
155 fn test_add_from_impl_already_exists() { 155 fn test_add_from_impl_already_exists() {
156 check_assist_not_applicable( 156 covers!(test_add_from_impl_already_exists);
157 add_from_impl_for_enum, 157 check_not_applicable(
158 r#"enum A { <|>One(u32), } 158 r#"
159enum A { <|>One(u32), }
159 160
160impl From<u32> for A { 161impl From<u32> for A {
161 fn from(v: u32) -> Self { 162 fn from(v: u32) -> Self {
162 A::One(v) 163 A::One(v)
163 } 164 }
164} 165}
165 166"#,
166pub trait From<T> {
167 fn from(T) -> Self;
168}"#,
169 ); 167 );
170 } 168 }
171 169