|
| 1 | +use ra_ide_db::RootDatabase; |
1 | 2 | use ra_syntax::{ |
2 | 3 | ast::{self, AstNode, NameOwner}, |
3 | 4 | TextSize, |
4 | 5 | }; |
5 | 6 | use stdx::format_to; |
6 | 7 |
|
7 | | -use crate::{Assist, AssistCtx, AssistId}; |
8 | | -use ra_ide_db::RootDatabase; |
| 8 | +use crate::{utils::FamousDefs, Assist, AssistCtx, AssistId}; |
| 9 | +use test_utils::tested_by; |
9 | 10 |
|
10 | 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 | 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 | 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 | 76 | sema: &'_ hir::Semantics<'_, RootDatabase>, |
75 | 77 | variant: &ast::EnumVariant, |
76 | | -) -> bool { |
77 | | - let scope = sema.scope(&variant.syntax()); |
| 78 | +) -> Option<()> { |
| 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"); |
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 | | - }; |
| 83 | + let from_trait = FamousDefs(sema, krate).core_convert_From()?; |
88 | 84 |
|
89 | | - let e: hir::Enum = match sema.to_def(&variant.parent_enum()) { |
90 | | - Some(e) => e, |
91 | | - None => return false, |
92 | | - }; |
93 | | - let e_ty = e.ty(sema.db); |
| 85 | + let enum_type = enum_.ty(sema.db); |
94 | 86 |
|
95 | | - let hir_enum_var: hir::EnumVariant = match sema.to_def(variant) { |
96 | | - Some(ev) => ev, |
97 | | - None => return false, |
98 | | - }; |
99 | | - let var_ty = hir_enum_var.fields(sema.db)[0].signature_ty(sema.db); |
| 87 | + let wrapped_type = variant.fields(sema.db).get(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 | 96 | #[cfg(test)] |
105 | 97 | mod tests { |
106 | 98 | use super::*; |
| 99 | + |
107 | 100 | use crate::helpers::{check_assist, check_assist_not_applicable}; |
| 101 | + use test_utils::covers; |
108 | 102 |
|
109 | 103 | #[test] |
110 | 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 | 139 | #[test] |
140 | 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 | 144 | #[test] |
145 | 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 | 149 | #[test] |
150 | 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 | 154 | #[test] |
155 | 155 | fn test_add_from_impl_already_exists() { |
156 | | - check_assist_not_applicable( |
157 | | - add_from_impl_for_enum, |
158 | | - r#"enum A { <|>One(u32), } |
| 156 | + covers!(test_add_from_impl_already_exists); |
| 157 | + check_not_applicable( |
| 158 | + r#" |
| 159 | +enum A { <|>One(u32), } |
159 | 160 |
|
160 | 161 | impl From<u32> for A { |
161 | 162 | fn from(v: u32) -> Self { |
162 | 163 | A::One(v) |
163 | 164 | } |
164 | 165 | } |
165 | | -
|
166 | | -pub trait From<T> { |
167 | | - fn from(T) -> Self; |
168 | | -}"#, |
| 166 | +"#, |
169 | 167 | ); |
170 | 168 | } |
171 | 169 |
|
|
0 commit comments