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