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