diff options
author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2020-04-29 14:03:40 +0100 |
---|---|---|
committer | GitHub <[email protected]> | 2020-04-29 14:03:40 +0100 |
commit | 12aae7771dc220a62d1323ac6a30ddf215fe2b92 (patch) | |
tree | 429968c8f7e4da8c54673b645f5d1de072bc7e1d /crates/ra_assists/src/handlers | |
parent | 69cf9fcc0aa452f144a565760d161dde523abe08 (diff) | |
parent | b4dd4752570d5f1ba24f7ffda69be4b1c935cd04 (diff) |
Merge #4208
4208: More principled approach for finding From trait r=matklad a=matklad
bors r+
🤖
Co-authored-by: Aleksey Kladov <[email protected]>
Diffstat (limited to 'crates/ra_assists/src/handlers')
-rw-r--r-- | crates/ra_assists/src/handlers/add_from_impl_for_enum.rs | 70 |
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 @@ | |||
1 | use ra_ide_db::RootDatabase; | ||
1 | use ra_syntax::{ | 2 | use ra_syntax::{ |
2 | ast::{self, AstNode, NameOwner}, | 3 | ast::{self, AstNode, NameOwner}, |
3 | TextSize, | 4 | TextSize, |
4 | }; | 5 | }; |
5 | use stdx::format_to; | 6 | use stdx::format_to; |
6 | 7 | ||
7 | use crate::{Assist, AssistCtx, AssistId}; | 8 | use crate::{utils::FamousDefs, Assist, AssistCtx, AssistId}; |
8 | use ra_ide_db::RootDatabase; | 9 | use 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 | ||
73 | fn already_has_from_impl( | 75 | fn 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)] |
105 | mod tests { | 97 | mod 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#" |
159 | enum A { <|>One(u32), } | ||
159 | 160 | ||
160 | impl From<u32> for A { | 161 | impl 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 | "#, | |
166 | pub trait From<T> { | ||
167 | fn from(T) -> Self; | ||
168 | }"#, | ||
169 | ); | 167 | ); |
170 | } | 168 | } |
171 | 169 | ||