]> git.lizzy.rs Git - rust.git/blob - src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_type_alias.rs
Auto merge of #103913 - Neutron3529:patch-1, r=thomcc
[rust.git] / src / tools / rust-analyzer / crates / ide-assists / src / handlers / inline_type_alias.rs
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 // }
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 // ```
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 {
158     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
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 {
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 {
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]
296 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
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 {
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
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
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
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]
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]
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]
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]
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]
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]
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]
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]
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]
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]
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]
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]
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]
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]
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]
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]
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]
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]
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]
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]
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]
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]
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]
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]
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]
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]
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]
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 }