1 // Some ideas for future improvements:
2 // - Support replacing aliases which are used in expressions, e.g. `A::new()`.
3 // - Remove unused aliases if there are no longer any users, see inline_call.rs.
4
5 use hir::{HasSource, PathResolution};
6 use ide_db::{
7 defs::Definition, imports::insert_use::ast_to_remove_for_path_in_use_stmt,
8 search::FileReference,
9 };
10 use itertools::Itertools;
11 use std::collections::HashMap;
12 use syntax::{
13 ast::{self, make, HasGenericParams, HasName},
14 ted, AstNode, NodeOrToken, SyntaxNode,
15 };
16
17 use crate::{
18 assist_context::{AssistContext, Assists},
19 AssistId, AssistKind,
20 };
21
22 use super::inline_call::split_refs_and_uses;
23
24 // Assist: inline_type_alias_uses
25 //
26 // Inline a type alias into all of its uses where possible.
27 //
28 // ```
29 // type $0A = i32;
30 // fn id(x: A) -> A {
31 // x
32 // };
33 // fn foo() {
34 // let _: A = 3;
35 // }
36 // ```
37 // ->
38 // ```
39 //
40 // fn id(x: i32) -> i32 {
41 // x
42 // };
43 // fn foo() {
44 // let _: i32 = 3;
45 // }
inline_type_alias_uses(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()>46 pub(crate) fn inline_type_alias_uses(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
47 let name = ctx.find_node_at_offset::<ast::Name>()?;
48 let ast_alias = name.syntax().parent().and_then(ast::TypeAlias::cast)?;
49
50 let hir_alias = ctx.sema.to_def(&ast_alias)?;
51 let concrete_type = ast_alias.ty()?;
52
53 let usages = Definition::TypeAlias(hir_alias).usages(&ctx.sema);
54 if !usages.at_least_one() {
55 return None;
56 }
57
58 // until this is ok
59
60 acc.add(
61 AssistId("inline_type_alias_uses", AssistKind::RefactorInline),
62 "Inline type alias into all uses",
63 name.syntax().text_range(),
64 |builder| {
65 let usages = usages.all();
66 let mut definition_deleted = false;
67
68 let mut inline_refs_for_file = |file_id, refs: Vec<FileReference>| {
69 builder.edit_file(file_id);
70
71 let (path_types, path_type_uses) =
72 split_refs_and_uses(builder, refs, |path_type| {
73 path_type.syntax().ancestors().nth(3).and_then(ast::PathType::cast)
74 });
75
76 path_type_uses
77 .iter()
78 .flat_map(ast_to_remove_for_path_in_use_stmt)
79 .for_each(|x| builder.delete(x.syntax().text_range()));
80 for (target, replacement) in path_types.into_iter().filter_map(|path_type| {
81 let replacement = inline(&ast_alias, &path_type)?.to_text(&concrete_type);
82 let target = path_type.syntax().text_range();
83 Some((target, replacement))
84 }) {
85 builder.replace(target, replacement);
86 }
87
88 if file_id == ctx.file_id() {
89 builder.delete(ast_alias.syntax().text_range());
90 definition_deleted = true;
91 }
92 };
93
94 for (file_id, refs) in usages.into_iter() {
95 inline_refs_for_file(file_id, refs);
96 }
97 if !definition_deleted {
98 builder.edit_file(ctx.file_id());
99 builder.delete(ast_alias.syntax().text_range());
100 }
101 },
102 )
103 }
104
105 // Assist: inline_type_alias
106 //
107 // Replace a type alias with its concrete type.
108 //
109 // ```
110 // type A<T = u32> = Vec<T>;
111 //
112 // fn main() {
113 // let a: $0A;
114 // }
115 // ```
116 // ->
117 // ```
118 // type A<T = u32> = Vec<T>;
119 //
120 // fn main() {
121 // let a: Vec<u32>;
122 // }
123 // ```
inline_type_alias(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()>124 pub(crate) fn inline_type_alias(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
125 let alias_instance = ctx.find_node_at_offset::<ast::PathType>()?;
126 let concrete_type;
127 let replacement;
128 match alias_instance.path()?.as_single_name_ref() {
129 Some(nameref) if nameref.Self_token().is_some() => {
130 match ctx.sema.resolve_path(&alias_instance.path()?)? {
131 PathResolution::SelfType(imp) => {
132 concrete_type = imp.source(ctx.db())?.value.self_ty()?;
133 }
134 // FIXME: should also work in ADT definitions
135 _ => return None,
136 }
137
138 replacement = Replacement::Plain;
139 }
140 _ => {
141 let alias = get_type_alias(ctx, &alias_instance)?;
142 concrete_type = alias.ty()?;
143 replacement = inline(&alias, &alias_instance)?;
144 }
145 }
146
147 let target = alias_instance.syntax().text_range();
148
149 acc.add(
150 AssistId("inline_type_alias", AssistKind::RefactorInline),
151 "Inline type alias",
152 target,
153 |builder| builder.replace(target, replacement.to_text(&concrete_type)),
154 )
155 }
156
157 impl Replacement {
to_text(&self, concrete_type: &ast::Type) -> String158 fn to_text(&self, concrete_type: &ast::Type) -> String {
159 match self {
160 Replacement::Generic { lifetime_map, const_and_type_map } => {
161 create_replacement(lifetime_map, const_and_type_map, concrete_type)
162 }
163 Replacement::Plain => concrete_type.to_string(),
164 }
165 }
166 }
167
168 enum Replacement {
169 Generic { lifetime_map: LifetimeMap, const_and_type_map: ConstAndTypeMap },
170 Plain,
171 }
172
inline(alias_def: &ast::TypeAlias, alias_instance: &ast::PathType) -> Option<Replacement>173 fn inline(alias_def: &ast::TypeAlias, alias_instance: &ast::PathType) -> Option<Replacement> {
174 let repl = if let Some(alias_generics) = alias_def.generic_param_list() {
175 if alias_generics.generic_params().next().is_none() {
176 cov_mark::hit!(no_generics_params);
177 return None;
178 }
179 let instance_args =
180 alias_instance.syntax().descendants().find_map(ast::GenericArgList::cast);
181
182 Replacement::Generic {
183 lifetime_map: LifetimeMap::new(&instance_args, &alias_generics)?,
184 const_and_type_map: ConstAndTypeMap::new(&instance_args, &alias_generics)?,
185 }
186 } else {
187 Replacement::Plain
188 };
189 Some(repl)
190 }
191
192 struct LifetimeMap(HashMap<String, ast::Lifetime>);
193
194 impl LifetimeMap {
new( instance_args: &Option<ast::GenericArgList>, alias_generics: &ast::GenericParamList, ) -> Option<Self>195 fn new(
196 instance_args: &Option<ast::GenericArgList>,
197 alias_generics: &ast::GenericParamList,
198 ) -> Option<Self> {
199 let mut inner = HashMap::new();
200
201 let wildcard_lifetime = make::lifetime("'_");
202 let lifetimes = alias_generics
203 .lifetime_params()
204 .filter_map(|lp| lp.lifetime())
205 .map(|l| l.to_string())
206 .collect_vec();
207
208 for lifetime in &lifetimes {
209 inner.insert(lifetime.to_string(), wildcard_lifetime.clone());
210 }
211
212 if let Some(instance_generic_args_list) = &instance_args {
213 for (index, lifetime) in instance_generic_args_list
214 .lifetime_args()
215 .filter_map(|arg| arg.lifetime())
216 .enumerate()
217 {
218 let key = match lifetimes.get(index) {
219 Some(key) => key,
220 None => {
221 cov_mark::hit!(too_many_lifetimes);
222 return None;
223 }
224 };
225
226 inner.insert(key.clone(), lifetime);
227 }
228 }
229
230 Some(Self(inner))
231 }
232 }
233
234 struct ConstAndTypeMap(HashMap<String, SyntaxNode>);
235
236 impl ConstAndTypeMap {
new( instance_args: &Option<ast::GenericArgList>, alias_generics: &ast::GenericParamList, ) -> Option<Self>237 fn new(
238 instance_args: &Option<ast::GenericArgList>,
239 alias_generics: &ast::GenericParamList,
240 ) -> Option<Self> {
241 let mut inner = HashMap::new();
242 let instance_generics = generic_args_to_const_and_type_generics(instance_args);
243 let alias_generics = generic_param_list_to_const_and_type_generics(alias_generics);
244
245 if instance_generics.len() > alias_generics.len() {
246 cov_mark::hit!(too_many_generic_args);
247 return None;
248 }
249
250 // Any declaration generics that don't have a default value must have one
251 // provided by the instance.
252 for (i, declaration_generic) in alias_generics.iter().enumerate() {
253 let key = declaration_generic.replacement_key()?;
254
255 if let Some(instance_generic) = instance_generics.get(i) {
256 inner.insert(key, instance_generic.replacement_value()?);
257 } else if let Some(value) = declaration_generic.replacement_value() {
258 inner.insert(key, value);
259 } else {
260 cov_mark::hit!(missing_replacement_param);
261 return None;
262 }
263 }
264
265 Some(Self(inner))
266 }
267 }
268
269 /// This doesn't attempt to ensure specified generics are compatible with those
270 /// required by the type alias, other than lifetimes which must either all be
271 /// specified or all omitted. It will replace TypeArgs with ConstArgs and vice
272 /// versa if they're in the wrong position. It supports partially specified
273 /// generics.
274 ///
275 /// 1. Map the provided instance's generic args to the type alias's generic
276 /// params:
277 ///
278 /// ```
279 /// type A<'a, const N: usize, T = u64> = &'a [T; N];
280 /// ^ alias generic params
281 /// let a: A<100>;
282 /// ^ instance generic args
283 /// ```
284 ///
285 /// generic['a] = '_ due to omission
286 /// generic[N] = 100 due to the instance arg
287 /// generic[T] = u64 due to the default param
288 ///
289 /// 2. Copy the concrete type and substitute in each found mapping:
290 ///
291 /// &'_ [u64; 100]
292 ///
293 /// 3. Remove wildcard lifetimes entirely:
294 ///
295 /// &[u64; 100]
create_replacement( lifetime_map: &LifetimeMap, const_and_type_map: &ConstAndTypeMap, concrete_type: &ast::Type, ) -> String296 fn create_replacement(
297 lifetime_map: &LifetimeMap,
298 const_and_type_map: &ConstAndTypeMap,
299 concrete_type: &ast::Type,
300 ) -> String {
301 let updated_concrete_type = concrete_type.clone_for_update();
302 let mut replacements = Vec::new();
303 let mut removals = Vec::new();
304
305 for syntax in updated_concrete_type.syntax().descendants() {
306 let syntax_string = syntax.to_string();
307 let syntax_str = syntax_string.as_str();
308
309 if let Some(old_lifetime) = ast::Lifetime::cast(syntax.clone()) {
310 if let Some(new_lifetime) = lifetime_map.0.get(&old_lifetime.to_string()) {
311 if new_lifetime.text() == "'_" {
312 removals.push(NodeOrToken::Node(syntax.clone()));
313
314 if let Some(ws) = syntax.next_sibling_or_token() {
315 removals.push(ws.clone());
316 }
317
318 continue;
319 }
320
321 replacements.push((syntax.clone(), new_lifetime.syntax().clone_for_update()));
322 }
323 } else if let Some(replacement_syntax) = const_and_type_map.0.get(syntax_str) {
324 let new_string = replacement_syntax.to_string();
325 let new = if new_string == "_" {
326 make::wildcard_pat().syntax().clone_for_update()
327 } else {
328 replacement_syntax.clone_for_update()
329 };
330
331 replacements.push((syntax.clone(), new));
332 }
333 }
334
335 for (old, new) in replacements {
336 ted::replace(old, new);
337 }
338
339 for syntax in removals {
340 ted::remove(syntax);
341 }
342
343 updated_concrete_type.to_string()
344 }
345
get_type_alias(ctx: &AssistContext<'_>, path: &ast::PathType) -> Option<ast::TypeAlias>346 fn get_type_alias(ctx: &AssistContext<'_>, path: &ast::PathType) -> Option<ast::TypeAlias> {
347 let resolved_path = ctx.sema.resolve_path(&path.path()?)?;
348
349 // We need the generics in the correct order to be able to map any provided
350 // instance generics to declaration generics. The `hir::TypeAlias` doesn't
351 // keep the order, so we must get the `ast::TypeAlias` from the hir
352 // definition.
353 if let PathResolution::Def(hir::ModuleDef::TypeAlias(ta)) = resolved_path {
354 Some(ctx.sema.source(ta)?.value)
355 } else {
356 None
357 }
358 }
359
360 enum ConstOrTypeGeneric {
361 ConstArg(ast::ConstArg),
362 TypeArg(ast::TypeArg),
363 ConstParam(ast::ConstParam),
364 TypeParam(ast::TypeParam),
365 }
366
367 impl ConstOrTypeGeneric {
replacement_key(&self) -> Option<String>368 fn replacement_key(&self) -> Option<String> {
369 // Only params are used as replacement keys.
370 match self {
371 ConstOrTypeGeneric::ConstParam(cp) => Some(cp.name()?.to_string()),
372 ConstOrTypeGeneric::TypeParam(tp) => Some(tp.name()?.to_string()),
373 _ => None,
374 }
375 }
376
replacement_value(&self) -> Option<SyntaxNode>377 fn replacement_value(&self) -> Option<SyntaxNode> {
378 Some(match self {
379 ConstOrTypeGeneric::ConstArg(ca) => ca.expr()?.syntax().clone(),
380 ConstOrTypeGeneric::TypeArg(ta) => ta.syntax().clone(),
381 ConstOrTypeGeneric::ConstParam(cp) => cp.default_val()?.syntax().clone(),
382 ConstOrTypeGeneric::TypeParam(tp) => tp.default_type()?.syntax().clone(),
383 })
384 }
385 }
386
generic_param_list_to_const_and_type_generics( generics: &ast::GenericParamList, ) -> Vec<ConstOrTypeGeneric>387 fn generic_param_list_to_const_and_type_generics(
388 generics: &ast::GenericParamList,
389 ) -> Vec<ConstOrTypeGeneric> {
390 let mut others = Vec::new();
391
392 for param in generics.generic_params() {
393 match param {
394 ast::GenericParam::LifetimeParam(_) => {}
395 ast::GenericParam::ConstParam(cp) => {
396 others.push(ConstOrTypeGeneric::ConstParam(cp));
397 }
398 ast::GenericParam::TypeParam(tp) => others.push(ConstOrTypeGeneric::TypeParam(tp)),
399 }
400 }
401
402 others
403 }
404
generic_args_to_const_and_type_generics( generics: &Option<ast::GenericArgList>, ) -> Vec<ConstOrTypeGeneric>405 fn generic_args_to_const_and_type_generics(
406 generics: &Option<ast::GenericArgList>,
407 ) -> Vec<ConstOrTypeGeneric> {
408 let mut others = Vec::new();
409
410 // It's fine for there to be no instance generics because the declaration
411 // might have default values or they might be inferred.
412 if let Some(generics) = generics {
413 for arg in generics.generic_args() {
414 match arg {
415 ast::GenericArg::TypeArg(ta) => {
416 others.push(ConstOrTypeGeneric::TypeArg(ta));
417 }
418 ast::GenericArg::ConstArg(ca) => {
419 others.push(ConstOrTypeGeneric::ConstArg(ca));
420 }
421 _ => {}
422 }
423 }
424 }
425
426 others
427 }
428
429 #[cfg(test)]
430 mod test {
431 use super::*;
432 use crate::tests::{check_assist, check_assist_not_applicable};
433
434 #[test]
empty_generic_params()435 fn empty_generic_params() {
436 cov_mark::check!(no_generics_params);
437 check_assist_not_applicable(
438 inline_type_alias,
439 r#"
440 type A<> = T;
441 fn main() {
442 let a: $0A<u32>;
443 }
444 "#,
445 );
446 }
447
448 #[test]
too_many_generic_args()449 fn too_many_generic_args() {
450 cov_mark::check!(too_many_generic_args);
451 check_assist_not_applicable(
452 inline_type_alias,
453 r#"
454 type A<T> = T;
455 fn main() {
456 let a: $0A<u32, u64>;
457 }
458 "#,
459 );
460 }
461
462 #[test]
too_many_lifetimes()463 fn too_many_lifetimes() {
464 cov_mark::check!(too_many_lifetimes);
465 check_assist_not_applicable(
466 inline_type_alias,
467 r#"
468 type A<'a> = &'a &'b u32;
469 fn f<'a>() {
470 let a: $0A<'a, 'b> = 0;
471 }
472 "#,
473 );
474 }
475
476 // This must be supported in order to support "inline_alias_to_users" or
477 // whatever it will be called.
478 #[test]
alias_as_expression_ignored()479 fn alias_as_expression_ignored() {
480 check_assist_not_applicable(
481 inline_type_alias,
482 r#"
483 type A = Vec<u32>;
484 fn main() {
485 let a: A = $0A::new();
486 }
487 "#,
488 );
489 }
490
491 #[test]
primitive_arg()492 fn primitive_arg() {
493 check_assist(
494 inline_type_alias,
495 r#"
496 type A<T> = T;
497 fn main() {
498 let a: $0A<u32> = 0;
499 }
500 "#,
501 r#"
502 type A<T> = T;
503 fn main() {
504 let a: u32 = 0;
505 }
506 "#,
507 );
508 }
509
510 #[test]
no_generic_replacements()511 fn no_generic_replacements() {
512 check_assist(
513 inline_type_alias,
514 r#"
515 type A = Vec<u32>;
516 fn main() {
517 let a: $0A;
518 }
519 "#,
520 r#"
521 type A = Vec<u32>;
522 fn main() {
523 let a: Vec<u32>;
524 }
525 "#,
526 );
527 }
528
529 #[test]
param_expression()530 fn param_expression() {
531 check_assist(
532 inline_type_alias,
533 r#"
534 type A<const N: usize = { 1 }> = [u32; N];
535 fn main() {
536 let a: $0A;
537 }
538 "#,
539 r#"
540 type A<const N: usize = { 1 }> = [u32; N];
541 fn main() {
542 let a: [u32; { 1 }];
543 }
544 "#,
545 );
546 }
547
548 #[test]
param_default_value()549 fn param_default_value() {
550 check_assist(
551 inline_type_alias,
552 r#"
553 type A<const N: usize = 1> = [u32; N];
554 fn main() {
555 let a: $0A;
556 }
557 "#,
558 r#"
559 type A<const N: usize = 1> = [u32; N];
560 fn main() {
561 let a: [u32; 1];
562 }
563 "#,
564 );
565 }
566
567 #[test]
all_param_types()568 fn all_param_types() {
569 check_assist(
570 inline_type_alias,
571 r#"
572 struct Struct<const C: usize>;
573 type A<'inner1, 'outer1, Outer1, const INNER1: usize, Inner1: Clone, const OUTER1: usize> = (Struct<INNER1>, Struct<OUTER1>, Outer1, &'inner1 (), Inner1, &'outer1 ());
574 fn foo<'inner2, 'outer2, Outer2, const INNER2: usize, Inner2, const OUTER2: usize>() {
575 let a: $0A<'inner2, 'outer2, Outer2, INNER2, Inner2, OUTER2>;
576 }
577 "#,
578 r#"
579 struct Struct<const C: usize>;
580 type A<'inner1, 'outer1, Outer1, const INNER1: usize, Inner1: Clone, const OUTER1: usize> = (Struct<INNER1>, Struct<OUTER1>, Outer1, &'inner1 (), Inner1, &'outer1 ());
581 fn foo<'inner2, 'outer2, Outer2, const INNER2: usize, Inner2, const OUTER2: usize>() {
582 let a: (Struct<INNER2>, Struct<OUTER2>, Outer2, &'inner2 (), Inner2, &'outer2 ());
583 }
584 "#,
585 );
586 }
587
588 #[test]
omitted_lifetimes()589 fn omitted_lifetimes() {
590 check_assist(
591 inline_type_alias,
592 r#"
593 type A<'l, 'r> = &'l &'r u32;
594 fn main() {
595 let a: $0A;
596 }
597 "#,
598 r#"
599 type A<'l, 'r> = &'l &'r u32;
600 fn main() {
601 let a: &&u32;
602 }
603 "#,
604 );
605 }
606
607 #[test]
omitted_type()608 fn omitted_type() {
609 check_assist(
610 inline_type_alias,
611 r#"
612 type A<'r, 'l, T = u32> = &'l std::collections::HashMap<&'r str, T>;
613 fn main() {
614 let a: $0A<'_, '_>;
615 }
616 "#,
617 r#"
618 type A<'r, 'l, T = u32> = &'l std::collections::HashMap<&'r str, T>;
619 fn main() {
620 let a: &std::collections::HashMap<&str, u32>;
621 }
622 "#,
623 );
624 }
625
626 #[test]
omitted_everything()627 fn omitted_everything() {
628 check_assist(
629 inline_type_alias,
630 r#"
631 type A<'r, 'l, T = u32> = &'l std::collections::HashMap<&'r str, T>;
632 fn main() {
633 let v = std::collections::HashMap<&str, u32>;
634 let a: $0A = &v;
635 }
636 "#,
637 r#"
638 type A<'r, 'l, T = u32> = &'l std::collections::HashMap<&'r str, T>;
639 fn main() {
640 let v = std::collections::HashMap<&str, u32>;
641 let a: &std::collections::HashMap<&str, u32> = &v;
642 }
643 "#,
644 );
645 }
646
647 // This doesn't actually cause the GenericArgsList to contain a AssocTypeArg.
648 #[test]
arg_associated_type()649 fn arg_associated_type() {
650 check_assist(
651 inline_type_alias,
652 r#"
653 trait Tra { type Assoc; fn a(); }
654 struct Str {}
655 impl Tra for Str {
656 type Assoc = u32;
657 fn a() {
658 type A<T> = Vec<T>;
659 let a: $0A<Self::Assoc>;
660 }
661 }
662 "#,
663 r#"
664 trait Tra { type Assoc; fn a(); }
665 struct Str {}
666 impl Tra for Str {
667 type Assoc = u32;
668 fn a() {
669 type A<T> = Vec<T>;
670 let a: Vec<Self::Assoc>;
671 }
672 }
673 "#,
674 );
675 }
676
677 #[test]
param_default_associated_type()678 fn param_default_associated_type() {
679 check_assist(
680 inline_type_alias,
681 r#"
682 trait Tra { type Assoc; fn a() }
683 struct Str {}
684 impl Tra for Str {
685 type Assoc = u32;
686 fn a() {
687 type A<T = Self::Assoc> = Vec<T>;
688 let a: $0A;
689 }
690 }
691 "#,
692 r#"
693 trait Tra { type Assoc; fn a() }
694 struct Str {}
695 impl Tra for Str {
696 type Assoc = u32;
697 fn a() {
698 type A<T = Self::Assoc> = Vec<T>;
699 let a: Vec<Self::Assoc>;
700 }
701 }
702 "#,
703 );
704 }
705
706 #[test]
function_pointer()707 fn function_pointer() {
708 check_assist(
709 inline_type_alias,
710 r#"
711 type A = fn(u32);
712 fn foo(a: u32) {}
713 fn main() {
714 let a: $0A = foo;
715 }
716 "#,
717 r#"
718 type A = fn(u32);
719 fn foo(a: u32) {}
720 fn main() {
721 let a: fn(u32) = foo;
722 }
723 "#,
724 );
725 }
726
727 #[test]
closure()728 fn closure() {
729 check_assist(
730 inline_type_alias,
731 r#"
732 type A = Box<dyn FnOnce(u32) -> u32>;
733 fn main() {
734 let a: $0A = Box::new(|_| 0);
735 }
736 "#,
737 r#"
738 type A = Box<dyn FnOnce(u32) -> u32>;
739 fn main() {
740 let a: Box<dyn FnOnce(u32) -> u32> = Box::new(|_| 0);
741 }
742 "#,
743 );
744 }
745
746 // Type aliases can't be used in traits, but someone might use the assist to
747 // fix the error.
748 #[test]
bounds()749 fn bounds() {
750 check_assist(
751 inline_type_alias,
752 r#"type A = std::io::Write; fn f<T>() where T: $0A {}"#,
753 r#"type A = std::io::Write; fn f<T>() where T: std::io::Write {}"#,
754 );
755 }
756
757 #[test]
function_parameter()758 fn function_parameter() {
759 check_assist(
760 inline_type_alias,
761 r#"
762 type A = std::io::Write;
763 fn f(a: impl $0A) {}
764 "#,
765 r#"
766 type A = std::io::Write;
767 fn f(a: impl std::io::Write) {}
768 "#,
769 );
770 }
771
772 #[test]
arg_expression()773 fn arg_expression() {
774 check_assist(
775 inline_type_alias,
776 r#"
777 type A<const N: usize> = [u32; N];
778 fn main() {
779 let a: $0A<{ 1 + 1 }>;
780 }
781 "#,
782 r#"
783 type A<const N: usize> = [u32; N];
784 fn main() {
785 let a: [u32; { 1 + 1 }];
786 }
787 "#,
788 )
789 }
790
791 #[test]
alias_instance_generic_path()792 fn alias_instance_generic_path() {
793 check_assist(
794 inline_type_alias,
795 r#"
796 type A<const N: usize> = [u32; N];
797 fn main() {
798 let a: $0A<u32::MAX>;
799 }
800 "#,
801 r#"
802 type A<const N: usize> = [u32; N];
803 fn main() {
804 let a: [u32; u32::MAX];
805 }
806 "#,
807 )
808 }
809
810 #[test]
generic_type()811 fn generic_type() {
812 check_assist(
813 inline_type_alias,
814 r#"
815 type A = String;
816 fn f(a: Vec<$0A>) {}
817 "#,
818 r#"
819 type A = String;
820 fn f(a: Vec<String>) {}
821 "#,
822 );
823 }
824
825 #[test]
missing_replacement_param()826 fn missing_replacement_param() {
827 cov_mark::check!(missing_replacement_param);
828 check_assist_not_applicable(
829 inline_type_alias,
830 r#"
831 type A<U> = Vec<T>;
832 fn main() {
833 let a: $0A;
834 }
835 "#,
836 );
837 }
838
839 #[test]
full_path_type_is_replaced()840 fn full_path_type_is_replaced() {
841 check_assist(
842 inline_type_alias,
843 r#"
844 mod foo {
845 pub type A = String;
846 }
847 fn main() {
848 let a: foo::$0A;
849 }
850 "#,
851 r#"
852 mod foo {
853 pub type A = String;
854 }
855 fn main() {
856 let a: String;
857 }
858 "#,
859 );
860 }
861
862 #[test]
inline_self_type()863 fn inline_self_type() {
864 check_assist(
865 inline_type_alias,
866 r#"
867 struct Strukt;
868
869 impl Strukt {
870 fn new() -> Self$0 {}
871 }
872 "#,
873 r#"
874 struct Strukt;
875
876 impl Strukt {
877 fn new() -> Strukt {}
878 }
879 "#,
880 );
881 check_assist(
882 inline_type_alias,
883 r#"
884 struct Strukt<'a, T, const C: usize>(&'a [T; C]);
885
886 impl<T, const C: usize> Strukt<'_, T, C> {
887 fn new() -> Self$0 {}
888 }
889 "#,
890 r#"
891 struct Strukt<'a, T, const C: usize>(&'a [T; C]);
892
893 impl<T, const C: usize> Strukt<'_, T, C> {
894 fn new() -> Strukt<'_, T, C> {}
895 }
896 "#,
897 );
898 check_assist(
899 inline_type_alias,
900 r#"
901 struct Strukt<'a, T, const C: usize>(&'a [T; C]);
902
903 trait Tr<'b, T> {}
904
905 impl<T, const C: usize> Tr<'static, u8> for Strukt<'_, T, C> {
906 fn new() -> Self$0 {}
907 }
908 "#,
909 r#"
910 struct Strukt<'a, T, const C: usize>(&'a [T; C]);
911
912 trait Tr<'b, T> {}
913
914 impl<T, const C: usize> Tr<'static, u8> for Strukt<'_, T, C> {
915 fn new() -> Strukt<'_, T, C> {}
916 }
917 "#,
918 );
919
920 check_assist_not_applicable(
921 inline_type_alias,
922 r#"
923 trait Tr {
924 fn new() -> Self$0;
925 }
926 "#,
927 );
928 }
929
930 mod inline_type_alias_uses {
931 use crate::{handlers::inline_type_alias::inline_type_alias_uses, tests::check_assist};
932
933 #[test]
inline_uses()934 fn inline_uses() {
935 check_assist(
936 inline_type_alias_uses,
937 r#"
938 type $0A = u32;
939
940 fn foo() {
941 let _: A = 3;
942 let _: A = 4;
943 }
944 "#,
945 r#"
946
947
948 fn foo() {
949 let _: u32 = 3;
950 let _: u32 = 4;
951 }
952 "#,
953 );
954 }
955
956 #[test]
inline_uses_across_files()957 fn inline_uses_across_files() {
958 check_assist(
959 inline_type_alias_uses,
960 r#"
961 //- /lib.rs
962 mod foo;
963 type $0T<E> = Vec<E>;
964 fn f() -> T<&str> {
965 vec!["hello"]
966 }
967
968 //- /foo.rs
969 use super::T;
970 fn foo() {
971 let _: T<i8> = Vec::new();
972 }
973 "#,
974 r#"
975 //- /lib.rs
976 mod foo;
977
978 fn f() -> Vec<&str> {
979 vec!["hello"]
980 }
981
982 //- /foo.rs
983
984 fn foo() {
985 let _: Vec<i8> = Vec::new();
986 }
987 "#,
988 );
989 }
990
991 #[test]
inline_uses_across_files_2()992 fn inline_uses_across_files_2() {
993 check_assist(
994 inline_type_alias_uses,
995 r#"
996 //- /lib.rs
997 mod foo;
998 type $0I = i32;
999
1000 //- /foo.rs
1001 use super::I;
1002 fn foo() {
1003 let _: I = 0;
1004 }
1005 "#,
1006 r#"
1007 //- /lib.rs
1008 mod foo;
1009
1010
1011 //- /foo.rs
1012
1013 fn foo() {
1014 let _: i32 = 0;
1015 }
1016 "#,
1017 );
1018 }
1019 }
1020 }
1021