Skip to content

Commit d7517d8

Browse files
committed
refactor: Veykril's code review suggestions
1 parent 5b712bd commit d7517d8

File tree

1 file changed

+126
-91
lines changed

1 file changed

+126
-91
lines changed

crates/ide_assists/src/handlers/inline_type_alias.rs

Lines changed: 126 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -46,11 +46,19 @@ pub(crate) fn inline_type_alias(acc: &mut Assists, ctx: &AssistContext) -> Optio
4646
let concrete_type = alias.ty()?;
4747

4848
let replacement = if let Some(alias_generics) = alias.generic_param_list() {
49-
get_replacement_for_generic_alias(
50-
alias_instance.syntax().descendants().find_map(ast::GenericArgList::cast),
51-
alias_generics,
49+
if alias_generics.generic_params().next().is_none() {
50+
cov_mark::hit!(no_generics_params);
51+
return None;
52+
}
53+
54+
let instance_args =
55+
alias_instance.syntax().descendants().find_map(ast::GenericArgList::cast);
56+
57+
create_replacement(
58+
&LifetimeMap::new(&instance_args, &alias_generics)?,
59+
&ConstAndTypeMap::new(&instance_args, &alias_generics)?,
5260
&concrete_type,
53-
)?
61+
)
5462
} else {
5563
concrete_type.to_string()
5664
};
@@ -67,6 +75,83 @@ pub(crate) fn inline_type_alias(acc: &mut Assists, ctx: &AssistContext) -> Optio
6775
)
6876
}
6977

78+
struct LifetimeMap(HashMap<String, ast::Lifetime>);
79+
80+
impl LifetimeMap {
81+
fn new(
82+
instance_args: &Option<ast::GenericArgList>,
83+
alias_generics: &ast::GenericParamList,
84+
) -> Option<Self> {
85+
let mut inner = HashMap::new();
86+
87+
let wildcard_lifetime = make::lifetime("'_");
88+
let lifetimes = alias_generics
89+
.lifetime_params()
90+
.filter_map(|lp| lp.lifetime())
91+
.map(|l| l.to_string())
92+
.collect_vec();
93+
94+
for lifetime in &lifetimes {
95+
inner.insert(lifetime.to_string(), wildcard_lifetime.clone());
96+
}
97+
98+
if let Some(instance_generic_args_list) = &instance_args {
99+
for (index, lifetime) in instance_generic_args_list
100+
.lifetime_args()
101+
.filter_map(|arg| arg.lifetime())
102+
.enumerate()
103+
{
104+
let key = match lifetimes.get(index) {
105+
Some(key) => key,
106+
None => {
107+
cov_mark::hit!(too_many_lifetimes);
108+
return None;
109+
}
110+
};
111+
112+
inner.insert(key.clone(), lifetime);
113+
}
114+
}
115+
116+
Some(Self(inner))
117+
}
118+
}
119+
120+
struct ConstAndTypeMap(HashMap<String, SyntaxNode>);
121+
122+
impl ConstAndTypeMap {
123+
fn new(
124+
instance_args: &Option<ast::GenericArgList>,
125+
alias_generics: &ast::GenericParamList,
126+
) -> Option<Self> {
127+
let mut inner = HashMap::new();
128+
let instance_generics = generic_args_to_const_and_type_generics(instance_args);
129+
let alias_generics = generic_param_list_to_const_and_type_generics(&alias_generics);
130+
131+
if instance_generics.len() > alias_generics.len() {
132+
cov_mark::hit!(too_many_generic_args);
133+
return None;
134+
}
135+
136+
// Any declaration generics that don't have a default value must have one
137+
// provided by the instance.
138+
for (i, declaration_generic) in alias_generics.iter().enumerate() {
139+
let key = declaration_generic.replacement_key()?;
140+
141+
if let Some(instance_generic) = instance_generics.get(i) {
142+
inner.insert(key, instance_generic.replacement_value()?);
143+
} else if let Some(value) = declaration_generic.replacement_value() {
144+
inner.insert(key, value);
145+
} else {
146+
cov_mark::hit!(missing_replacement_param);
147+
return None;
148+
}
149+
}
150+
151+
Some(Self(inner))
152+
}
153+
}
154+
70155
/// This doesn't attempt to ensure specified generics are compatible with those
71156
/// required by the type alias, other than lifetimes which must either all be
72157
/// specified or all omitted. It will replace TypeArgs with ConstArgs and vice
@@ -94,65 +179,11 @@ pub(crate) fn inline_type_alias(acc: &mut Assists, ctx: &AssistContext) -> Optio
94179
/// 3. Remove wildcard lifetimes entirely:
95180
///
96181
/// &[u64; 100]
97-
fn get_replacement_for_generic_alias(
98-
instance_generic_args_list: Option<ast::GenericArgList>,
99-
alias_generics: ast::GenericParamList,
182+
fn create_replacement(
183+
lifetime_map: &LifetimeMap,
184+
const_and_type_map: &ConstAndTypeMap,
100185
concrete_type: &ast::Type,
101-
) -> Option<String> {
102-
if alias_generics.generic_params().count() == 0 {
103-
cov_mark::hit!(no_generics_params);
104-
return None;
105-
}
106-
107-
let mut lifetime_mappings = HashMap::<&str, ast::Lifetime>::new();
108-
let mut other_mappings = HashMap::<String, SyntaxNode>::new();
109-
110-
let wildcard_lifetime = make::lifetime("'_");
111-
let alias_lifetimes = alias_generics.lifetime_params().map(|l| l.to_string()).collect_vec();
112-
for lifetime in &alias_lifetimes {
113-
lifetime_mappings.insert(lifetime, wildcard_lifetime.clone());
114-
}
115-
116-
if let Some(ref instance_generic_args_list) = instance_generic_args_list {
117-
for (index, lifetime) in instance_generic_args_list
118-
.lifetime_args()
119-
.map(|arg| arg.lifetime().expect("LifetimeArg has a Lifetime"))
120-
.enumerate()
121-
{
122-
if index >= alias_lifetimes.len() {
123-
cov_mark::hit!(too_many_lifetimes);
124-
return None;
125-
}
126-
127-
let key = &alias_lifetimes[index];
128-
129-
lifetime_mappings.insert(key, lifetime);
130-
}
131-
}
132-
133-
let instance_generics = generic_args_to_other_generics(instance_generic_args_list);
134-
let alias_generics = generic_param_list_to_other_generics(&alias_generics);
135-
136-
if instance_generics.len() > alias_generics.len() {
137-
cov_mark::hit!(too_many_generic_args);
138-
return None;
139-
}
140-
141-
// Any declaration generics that don't have a default value must have one
142-
// provided by the instance.
143-
for (i, declaration_generic) in alias_generics.iter().enumerate() {
144-
let key = declaration_generic.replacement_key();
145-
146-
if let Some(instance_generic) = instance_generics.get(i) {
147-
other_mappings.insert(key, instance_generic.replacement_value()?);
148-
} else if let Some(value) = declaration_generic.replacement_value() {
149-
other_mappings.insert(key, value);
150-
} else {
151-
cov_mark::hit!(missing_replacement_param);
152-
return None;
153-
}
154-
}
155-
186+
) -> String {
156187
let updated_concrete_type = concrete_type.clone_for_update();
157188
let mut replacements = Vec::new();
158189
let mut removals = Vec::new();
@@ -161,20 +192,21 @@ fn get_replacement_for_generic_alias(
161192
let syntax_string = syntax.to_string();
162193
let syntax_str = syntax_string.as_str();
163194

164-
if syntax.kind() == SyntaxKind::LIFETIME {
165-
let new = lifetime_mappings.get(syntax_str).expect("lifetime is mapped");
166-
if new.text() == "'_" {
167-
removals.push(NodeOrToken::Node(syntax.clone()));
195+
if let Some(old_lifetime) = ast::Lifetime::cast(syntax.clone()) {
196+
if let Some(new_lifetime) = lifetime_map.0.get(&old_lifetime.to_string()) {
197+
if new_lifetime.text() == "'_" {
198+
removals.push(NodeOrToken::Node(syntax.clone()));
199+
200+
if let Some(ws) = syntax.next_sibling_or_token() {
201+
removals.push(ws.clone());
202+
}
168203

169-
if let Some(ws) = syntax.next_sibling_or_token() {
170-
removals.push(ws.clone());
204+
continue;
171205
}
172206

173-
continue;
207+
replacements.push((syntax.clone(), new_lifetime.syntax().clone_for_update()));
174208
}
175-
176-
replacements.push((syntax.clone(), new.syntax().clone_for_update()));
177-
} else if let Some(replacement_syntax) = other_mappings.get(syntax_str) {
209+
} else if let Some(replacement_syntax) = const_and_type_map.0.get(syntax_str) {
178210
let new_string = replacement_syntax.to_string();
179211
let new = if new_string == "_" {
180212
make::wildcard_pat().syntax().clone_for_update()
@@ -194,7 +226,7 @@ fn get_replacement_for_generic_alias(
194226
ted::remove(syntax);
195227
}
196228

197-
Some(updated_concrete_type.to_string())
229+
updated_concrete_type.to_string()
198230
}
199231

200232
fn get_type_alias(ctx: &AssistContext, path: &ast::PathType) -> Option<ast::TypeAlias> {
@@ -205,57 +237,60 @@ fn get_type_alias(ctx: &AssistContext, path: &ast::PathType) -> Option<ast::Type
205237
// keep the order, so we must get the `ast::TypeAlias` from the hir
206238
// definition.
207239
if let PathResolution::Def(hir::ModuleDef::TypeAlias(ta)) = resolved_path {
208-
ast::TypeAlias::cast(ctx.sema.source(ta)?.syntax().value.clone())
240+
Some(ctx.sema.source(ta)?.value)
209241
} else {
210242
None
211243
}
212244
}
213245

214-
enum OtherGeneric {
246+
enum ConstOrTypeGeneric {
215247
ConstArg(ast::ConstArg),
216248
TypeArg(ast::TypeArg),
217249
ConstParam(ast::ConstParam),
218250
TypeParam(ast::TypeParam),
219251
}
220252

221-
impl OtherGeneric {
222-
fn replacement_key(&self) -> String {
253+
impl ConstOrTypeGeneric {
254+
fn replacement_key(&self) -> Option<String> {
223255
// Only params are used as replacement keys.
224256
match self {
225-
OtherGeneric::ConstArg(_) => unreachable!(),
226-
OtherGeneric::TypeArg(_) => unreachable!(),
227-
OtherGeneric::ConstParam(cp) => cp.name().expect("ConstParam has a name").to_string(),
228-
OtherGeneric::TypeParam(tp) => tp.name().expect("TypeParam has a name").to_string(),
257+
ConstOrTypeGeneric::ConstParam(cp) => Some(cp.name()?.to_string()),
258+
ConstOrTypeGeneric::TypeParam(tp) => Some(tp.name()?.to_string()),
259+
_ => None,
229260
}
230261
}
231262

232263
fn replacement_value(&self) -> Option<SyntaxNode> {
233264
Some(match self {
234-
OtherGeneric::ConstArg(ca) => ca.expr()?.syntax().clone(),
235-
OtherGeneric::TypeArg(ta) => ta.syntax().clone(),
236-
OtherGeneric::ConstParam(cp) => cp.default_val()?.syntax().clone(),
237-
OtherGeneric::TypeParam(tp) => tp.default_type()?.syntax().clone(),
265+
ConstOrTypeGeneric::ConstArg(ca) => ca.expr()?.syntax().clone(),
266+
ConstOrTypeGeneric::TypeArg(ta) => ta.syntax().clone(),
267+
ConstOrTypeGeneric::ConstParam(cp) => cp.default_val()?.syntax().clone(),
268+
ConstOrTypeGeneric::TypeParam(tp) => tp.default_type()?.syntax().clone(),
238269
})
239270
}
240271
}
241272

242-
fn generic_param_list_to_other_generics(generics: &ast::GenericParamList) -> Vec<OtherGeneric> {
273+
fn generic_param_list_to_const_and_type_generics(
274+
generics: &ast::GenericParamList,
275+
) -> Vec<ConstOrTypeGeneric> {
243276
let mut others = Vec::new();
244277

245278
for param in generics.generic_params() {
246279
match param {
247280
ast::GenericParam::LifetimeParam(_) => {}
248281
ast::GenericParam::ConstParam(cp) => {
249-
others.push(OtherGeneric::ConstParam(cp));
282+
others.push(ConstOrTypeGeneric::ConstParam(cp));
250283
}
251-
ast::GenericParam::TypeParam(tp) => others.push(OtherGeneric::TypeParam(tp)),
284+
ast::GenericParam::TypeParam(tp) => others.push(ConstOrTypeGeneric::TypeParam(tp)),
252285
}
253286
}
254287

255288
others
256289
}
257290

258-
fn generic_args_to_other_generics(generics: Option<ast::GenericArgList>) -> Vec<OtherGeneric> {
291+
fn generic_args_to_const_and_type_generics(
292+
generics: &Option<ast::GenericArgList>,
293+
) -> Vec<ConstOrTypeGeneric> {
259294
let mut others = Vec::new();
260295

261296
// It's fine for there to be no instance generics because the declaration
@@ -264,10 +299,10 @@ fn generic_args_to_other_generics(generics: Option<ast::GenericArgList>) -> Vec<
264299
for arg in generics.generic_args() {
265300
match arg {
266301
ast::GenericArg::TypeArg(ta) => {
267-
others.push(OtherGeneric::TypeArg(ta));
302+
others.push(ConstOrTypeGeneric::TypeArg(ta));
268303
}
269304
ast::GenericArg::ConstArg(ca) => {
270-
others.push(OtherGeneric::ConstArg(ca));
305+
others.push(ConstOrTypeGeneric::ConstArg(ca));
271306
}
272307
_ => {}
273308
}

0 commit comments

Comments
 (0)