1use hir::{HasSource, PathResolution};
6use ide_db::FxHashMap;
7use ide_db::{
8 defs::Definition, imports::insert_use::remove_use_tree_if_simple, search::FileReference,
9};
10use itertools::Itertools;
11use syntax::ast::syntax_factory::SyntaxFactory;
12use syntax::syntax_editor::SyntaxEditor;
13use syntax::{
14 AstNode, NodeOrToken, SyntaxKind, SyntaxNode, T,
15 ast::{self, HasGenericParams, HasName},
16};
17
18use crate::{
19 AssistId,
20 assist_context::{AssistContext, Assists},
21};
22
23use super::inline_call::split_refs_and_uses;
24
25pub(crate) fn inline_type_alias_uses(acc: &mut Assists, ctx: &AssistContext<'_, '_>) -> Option<()> {
49 let name = ctx.find_node_at_offset::<ast::Name>()?;
50 let ast_alias = name.syntax().parent().and_then(ast::TypeAlias::cast)?;
51
52 let hir_alias = ctx.sema.to_def(&ast_alias)?;
53 let concrete_type = ast_alias.ty()?;
54
55 let usages = Definition::TypeAlias(hir_alias).usages(&ctx.sema);
56 if !usages.at_least_one() {
57 return None;
58 }
59
60 acc.add(
63 AssistId::refactor_inline("inline_type_alias_uses"),
64 "Inline type alias into all uses",
65 name.syntax().text_range(),
66 |builder| {
67 let usages = usages.all();
68 let mut definition_deleted = false;
69
70 let mut inline_refs_for_file = |file_id, refs: Vec<FileReference>| {
71 let source = ctx.sema.parse(file_id);
72 let editor = builder.make_editor(source.syntax());
73
74 let (path_types, path_type_uses) = split_refs_and_uses(refs, |path_type| {
75 path_type.syntax().ancestors().nth(3).and_then(ast::PathType::cast)
76 });
77 path_type_uses
78 .iter()
79 .for_each(|use_tree| remove_use_tree_if_simple(use_tree, &editor));
80
81 for (target, replacement) in path_types.into_iter().filter_map(|path_type| {
82 let replacement =
83 inline(&ast_alias, &path_type)?.replace_generic(&concrete_type);
84 let target = path_type.syntax().clone();
85 Some((target, replacement))
86 }) {
87 editor.replace(target, replacement);
88 }
89
90 if file_id.file_id(ctx.db()) == ctx.vfs_file_id() {
91 editor.delete(ast_alias.syntax());
92 definition_deleted = true;
93 }
94 builder.add_file_edits(file_id.file_id(ctx.db()), editor);
95 };
96
97 for (file_id, refs) in usages.into_iter() {
98 inline_refs_for_file(file_id, refs);
99 }
100 if !definition_deleted {
101 let editor = builder.make_editor(ast_alias.syntax());
102 editor.delete(ast_alias.syntax());
103 builder.add_file_edits(ctx.vfs_file_id(), editor)
104 }
105 },
106 )
107}
108
109pub(crate) fn inline_type_alias(acc: &mut Assists, ctx: &AssistContext<'_, '_>) -> Option<()> {
129 let alias_instance = ctx.find_node_at_offset::<ast::PathType>()?;
130 let concrete_type;
131 let replacement;
132 match alias_instance.path()?.as_single_name_ref() {
133 Some(nameref) if nameref.Self_token().is_some() => {
134 match ctx.sema.resolve_path(&alias_instance.path()?)? {
135 PathResolution::SelfType(imp) => {
136 concrete_type = imp.source(ctx.db())?.value.self_ty()?;
137 }
138 _ => return None,
140 }
141
142 replacement = Replacement::Plain;
143 }
144 _ => {
145 let alias = get_type_alias(ctx, &alias_instance)?;
146 concrete_type = alias.ty()?;
147 replacement = inline(&alias, &alias_instance)?;
148 }
149 }
150
151 acc.add(
152 AssistId::refactor_inline("inline_type_alias"),
153 "Inline type alias",
154 alias_instance.syntax().text_range(),
155 |builder| {
156 let editor = builder.make_editor(alias_instance.syntax());
157 let replace = replacement.replace_generic(&concrete_type);
158 editor.replace(alias_instance.syntax(), replace);
159 builder.add_file_edits(ctx.vfs_file_id(), editor);
160 },
161 )
162}
163
164impl Replacement {
165 fn replace_generic(&self, concrete_type: &ast::Type) -> SyntaxNode {
166 match self {
167 Replacement::Generic { lifetime_map, const_and_type_map } => {
168 create_replacement(lifetime_map, const_and_type_map, concrete_type)
169 }
170 Replacement::Plain => concrete_type.syntax().clone(),
171 }
172 }
173}
174
175enum Replacement {
176 Generic { lifetime_map: LifetimeMap, const_and_type_map: ConstAndTypeMap },
177 Plain,
178}
179
180fn inline(alias_def: &ast::TypeAlias, alias_instance: &ast::PathType) -> Option<Replacement> {
181 let repl = if let Some(alias_generics) = alias_def.generic_param_list() {
182 if alias_generics.generic_params().next().is_none() {
183 cov_mark::hit!(no_generics_params);
184 return None;
185 }
186 let instance_args =
187 alias_instance.syntax().descendants().find_map(ast::GenericArgList::cast);
188
189 Replacement::Generic {
190 lifetime_map: LifetimeMap::new(&instance_args, &alias_generics)?,
191 const_and_type_map: ConstAndTypeMap::new(&instance_args, &alias_generics)?,
192 }
193 } else {
194 Replacement::Plain
195 };
196 Some(repl)
197}
198
199struct LifetimeMap(FxHashMap<String, ast::Lifetime>);
200
201impl LifetimeMap {
202 fn new(
203 instance_args: &Option<ast::GenericArgList>,
204 alias_generics: &ast::GenericParamList,
205 ) -> Option<Self> {
206 let mut inner = FxHashMap::default();
207 let make = SyntaxFactory::without_mappings();
208 let wildcard_lifetime = make.lifetime("'_");
209 let lifetimes = alias_generics
210 .lifetime_params()
211 .filter_map(|lp| lp.lifetime())
212 .map(|l| l.to_string())
213 .collect_vec();
214
215 for lifetime in &lifetimes {
216 inner.insert(lifetime.to_string(), wildcard_lifetime.clone());
217 }
218
219 if let Some(instance_generic_args_list) = &instance_args {
220 for (index, lifetime) in instance_generic_args_list
221 .lifetime_args()
222 .filter_map(|arg| arg.lifetime())
223 .enumerate()
224 {
225 let key = match lifetimes.get(index) {
226 Some(key) => key,
227 None => {
228 cov_mark::hit!(too_many_lifetimes);
229 return None;
230 }
231 };
232
233 inner.insert(key.clone(), lifetime);
234 }
235 }
236
237 Some(Self(inner))
238 }
239}
240
241struct ConstAndTypeMap(FxHashMap<String, SyntaxNode>);
242
243impl ConstAndTypeMap {
244 fn new(
245 instance_args: &Option<ast::GenericArgList>,
246 alias_generics: &ast::GenericParamList,
247 ) -> Option<Self> {
248 let mut inner = FxHashMap::default();
249 let instance_generics = generic_args_to_const_and_type_generics(instance_args);
250 let alias_generics = generic_param_list_to_const_and_type_generics(alias_generics);
251
252 if instance_generics.len() > alias_generics.len() {
253 cov_mark::hit!(too_many_generic_args);
254 return None;
255 }
256
257 for (i, declaration_generic) in alias_generics.iter().enumerate() {
260 let key = declaration_generic.replacement_key()?;
261
262 if let Some(instance_generic) = instance_generics.get(i) {
263 inner.insert(key, instance_generic.replacement_value()?);
264 } else if let Some(value) = declaration_generic.replacement_value() {
265 inner.insert(key, value);
266 } else {
267 cov_mark::hit!(missing_replacement_param);
268 return None;
269 }
270 }
271
272 Some(Self(inner))
273 }
274}
275
276fn create_replacement(
308 lifetime_map: &LifetimeMap,
309 const_and_type_map: &ConstAndTypeMap,
310 concrete_type: &ast::Type,
311) -> SyntaxNode {
312 let (editor, updated_concrete_type) = SyntaxEditor::new(concrete_type.syntax().clone());
313 let make = editor.make();
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 if let Some(lifetime_arg) =
323 old_lifetime.syntax().parent().and_then(ast::LifetimeArg::cast)
324 {
325 let lifetime_arg_syntax = lifetime_arg.syntax();
327 removals.push(NodeOrToken::Node(lifetime_arg_syntax.clone()));
328
329 let comma_and_ws: Vec<_> = lifetime_arg_syntax
331 .siblings_with_tokens(syntax::Direction::Next)
332 .skip(1)
333 .take_while(|it| it.as_token().is_some())
334 .take_while_inclusive(|it| it.kind() == T![,])
335 .collect();
336
337 if comma_and_ws.iter().any(|it| it.kind() == T![,]) {
338 removals.extend(comma_and_ws);
339 } else {
340 let comma_and_ws: Vec<_> = lifetime_arg_syntax
342 .siblings_with_tokens(syntax::Direction::Prev)
343 .skip(1)
344 .take_while(|it| it.as_token().is_some())
345 .take_while_inclusive(|it| it.kind() == T![,])
346 .collect();
347 removals.extend(comma_and_ws);
348 }
349 continue;
350 }
351 removals.push(NodeOrToken::Node(syntax.clone()));
352 if let Some(ws) = syntax.next_sibling_or_token()
353 && ws.kind() == SyntaxKind::WHITESPACE
354 {
355 removals.push(ws);
356 }
357 continue;
358 }
359
360 replacements.push((syntax.clone(), new_lifetime.syntax().clone()));
361 }
362 } else if let Some(name_ref) = ast::NameRef::cast(syntax.clone()) {
363 let Some(replacement_syntax) = const_and_type_map.0.get(&name_ref.to_string()) else {
364 continue;
365 };
366 let new_string = replacement_syntax.to_string();
367 let new = if new_string == "_" {
368 make.wildcard_pat().syntax().clone()
369 } else {
370 replacement_syntax.clone()
371 };
372
373 replacements.push((syntax.clone(), new));
374 }
375 }
376
377 removals.sort_by_key(|n| n.text_range().start());
379 removals.dedup();
380
381 let generic_arg_lists_to_check: Vec<_> =
383 updated_concrete_type.descendants().filter_map(ast::GenericArgList::cast).collect();
384
385 for generic_arg_list in generic_arg_lists_to_check {
386 let will_be_empty = generic_arg_list.generic_args().all(|arg| match arg {
387 ast::GenericArg::LifetimeArg(lt_arg) => removals.iter().any(|removal| {
388 if let NodeOrToken::Node(node) = removal { node == lt_arg.syntax() } else { false }
389 }),
390 _ => false,
391 });
392
393 if will_be_empty && generic_arg_list.generic_args().next().is_some() {
394 removals.retain(|removal| {
395 if let NodeOrToken::Node(node) = removal {
396 !node.ancestors().any(|anc| anc == *generic_arg_list.syntax())
397 } else {
398 true
399 }
400 });
401 removals.push(NodeOrToken::Node(generic_arg_list.syntax().clone()));
402 }
403 }
404
405 for (old, new) in replacements {
406 editor.replace(old, new);
407 }
408
409 for syntax in removals {
410 editor.delete(syntax);
411 }
412 editor.finish().new_root().clone()
413}
414
415fn get_type_alias(ctx: &AssistContext<'_, '_>, path: &ast::PathType) -> Option<ast::TypeAlias> {
416 let resolved_path = ctx.sema.resolve_path(&path.path()?)?;
417
418 if let PathResolution::Def(hir::ModuleDef::TypeAlias(ta)) = resolved_path {
423 Some(ctx.sema.source(ta)?.value)
424 } else {
425 None
426 }
427}
428
429enum ConstOrTypeGeneric {
430 ConstArg(ast::ConstArg),
431 TypeArg(ast::TypeArg),
432 ConstParam(ast::ConstParam),
433 TypeParam(ast::TypeParam),
434}
435
436impl ConstOrTypeGeneric {
437 fn replacement_key(&self) -> Option<String> {
438 match self {
440 ConstOrTypeGeneric::ConstParam(cp) => Some(cp.name()?.to_string()),
441 ConstOrTypeGeneric::TypeParam(tp) => Some(tp.name()?.to_string()),
442 _ => None,
443 }
444 }
445
446 fn replacement_value(&self) -> Option<SyntaxNode> {
447 Some(match self {
448 ConstOrTypeGeneric::ConstArg(ca) => ca.expr()?.syntax().clone(),
449 ConstOrTypeGeneric::TypeArg(ta) => ta.syntax().clone(),
450 ConstOrTypeGeneric::ConstParam(cp) => cp.default_val()?.syntax().clone(),
451 ConstOrTypeGeneric::TypeParam(tp) => tp.default_type()?.syntax().clone(),
452 })
453 }
454}
455
456fn generic_param_list_to_const_and_type_generics(
457 generics: &ast::GenericParamList,
458) -> Vec<ConstOrTypeGeneric> {
459 let mut others = Vec::new();
460
461 for param in generics.generic_params() {
462 match param {
463 ast::GenericParam::LifetimeParam(_) => {}
464 ast::GenericParam::ConstParam(cp) => {
465 others.push(ConstOrTypeGeneric::ConstParam(cp));
466 }
467 ast::GenericParam::TypeParam(tp) => others.push(ConstOrTypeGeneric::TypeParam(tp)),
468 }
469 }
470
471 others
472}
473
474fn generic_args_to_const_and_type_generics(
475 generics: &Option<ast::GenericArgList>,
476) -> Vec<ConstOrTypeGeneric> {
477 let mut others = Vec::new();
478
479 if let Some(generics) = generics {
482 for arg in generics.generic_args() {
483 match arg {
484 ast::GenericArg::TypeArg(ta) => {
485 others.push(ConstOrTypeGeneric::TypeArg(ta));
486 }
487 ast::GenericArg::ConstArg(ca) => {
488 others.push(ConstOrTypeGeneric::ConstArg(ca));
489 }
490 _ => {}
491 }
492 }
493 }
494
495 others
496}
497
498#[cfg(test)]
499mod test {
500 use super::*;
501 use crate::tests::{check_assist, check_assist_not_applicable};
502
503 #[test]
504 fn empty_generic_params() {
505 cov_mark::check!(no_generics_params);
506 check_assist_not_applicable(
507 inline_type_alias,
508 r#"
509type A<> = T;
510fn main() {
511 let a: $0A<u32>;
512}
513 "#,
514 );
515 }
516
517 #[test]
518 fn too_many_generic_args() {
519 cov_mark::check!(too_many_generic_args);
520 check_assist_not_applicable(
521 inline_type_alias,
522 r#"
523type A<T> = T;
524fn main() {
525 let a: $0A<u32, u64>;
526}
527 "#,
528 );
529 }
530
531 #[test]
532 fn too_many_lifetimes() {
533 cov_mark::check!(too_many_lifetimes);
534 check_assist_not_applicable(
535 inline_type_alias,
536 r#"
537type A<'a> = &'a &'b u32;
538fn f<'a>() {
539 let a: $0A<'a, 'b> = 0;
540}
541"#,
542 );
543 }
544
545 #[test]
548 fn alias_as_expression_ignored() {
549 check_assist_not_applicable(
550 inline_type_alias,
551 r#"
552type A = Vec<u32>;
553fn main() {
554 let a: A = $0A::new();
555}
556"#,
557 );
558 }
559
560 #[test]
561 fn primitive_arg() {
562 check_assist(
563 inline_type_alias,
564 r#"
565type A<T> = T;
566fn main() {
567 let a: $0A<u32> = 0;
568}
569"#,
570 r#"
571type A<T> = T;
572fn main() {
573 let a: u32 = 0;
574}
575"#,
576 );
577 }
578
579 #[test]
580 fn no_generic_replacements() {
581 check_assist(
582 inline_type_alias,
583 r#"
584type A = Vec<u32>;
585fn main() {
586 let a: $0A;
587}
588"#,
589 r#"
590type A = Vec<u32>;
591fn main() {
592 let a: Vec<u32>;
593}
594"#,
595 );
596 }
597
598 #[test]
599 fn param_expression() {
600 check_assist(
601 inline_type_alias,
602 r#"
603type A<const N: usize = { 1 }> = [u32; N];
604fn main() {
605 let a: $0A;
606}
607"#,
608 r#"
609type A<const N: usize = { 1 }> = [u32; N];
610fn main() {
611 let a: [u32; { 1 }];
612}
613"#,
614 );
615 }
616
617 #[test]
618 fn param_default_value() {
619 check_assist(
620 inline_type_alias,
621 r#"
622type A<const N: usize = 1> = [u32; N];
623fn main() {
624 let a: $0A;
625}
626"#,
627 r#"
628type A<const N: usize = 1> = [u32; N];
629fn main() {
630 let a: [u32; 1];
631}
632"#,
633 );
634 }
635
636 #[test]
637 fn all_param_types() {
638 check_assist(
639 inline_type_alias,
640 r#"
641struct Struct<const C: usize>;
642type A<'inner1, 'outer1, Outer1, const INNER1: usize, Inner1: Clone, const OUTER1: usize> = (Struct<INNER1>, Struct<OUTER1>, Outer1, &'inner1 (), Inner1, &'outer1 ());
643fn foo<'inner2, 'outer2, Outer2, const INNER2: usize, Inner2, const OUTER2: usize>() {
644 let a: $0A<'inner2, 'outer2, Outer2, INNER2, Inner2, OUTER2>;
645}
646"#,
647 r#"
648struct Struct<const C: usize>;
649type A<'inner1, 'outer1, Outer1, const INNER1: usize, Inner1: Clone, const OUTER1: usize> = (Struct<INNER1>, Struct<OUTER1>, Outer1, &'inner1 (), Inner1, &'outer1 ());
650fn foo<'inner2, 'outer2, Outer2, const INNER2: usize, Inner2, const OUTER2: usize>() {
651 let a: (Struct<INNER2>, Struct<OUTER2>, Outer2, &'inner2 (), Inner2, &'outer2 ());
652}
653"#,
654 );
655 }
656
657 #[test]
658 fn omitted_lifetimes() {
659 check_assist(
660 inline_type_alias,
661 r#"
662type A<'l, 'r> = &'l &'r u32;
663fn main() {
664 let a: $0A;
665}
666"#,
667 r#"
668type A<'l, 'r> = &'l &'r u32;
669fn main() {
670 let a: &&u32;
671}
672"#,
673 );
674 }
675
676 #[test]
677 fn omitted_type() {
678 check_assist(
679 inline_type_alias,
680 r#"
681type A<'r, 'l, T = u32> = &'l std::collections::HashMap<&'r str, T>;
682fn main() {
683 let a: $0A<'_, '_>;
684}
685"#,
686 r#"
687type A<'r, 'l, T = u32> = &'l std::collections::HashMap<&'r str, T>;
688fn main() {
689 let a: &std::collections::HashMap<&str, u32>;
690}
691"#,
692 );
693 }
694
695 #[test]
696 fn omitted_everything() {
697 check_assist(
698 inline_type_alias,
699 r#"
700type A<'r, 'l, T = u32> = &'l std::collections::HashMap<&'r str, T>;
701fn main() {
702 let v = std::collections::HashMap<&str, u32>;
703 let a: $0A = &v;
704}
705"#,
706 r#"
707type A<'r, 'l, T = u32> = &'l std::collections::HashMap<&'r str, T>;
708fn main() {
709 let v = std::collections::HashMap<&str, u32>;
710 let a: &std::collections::HashMap<&str, u32> = &v;
711}
712"#,
713 );
714 }
715
716 #[test]
718 fn arg_associated_type() {
719 check_assist(
720 inline_type_alias,
721 r#"
722trait Tra { type Assoc; fn a(); }
723struct Str {}
724impl Tra for Str {
725 type Assoc = u32;
726 fn a() {
727 type A<T> = Vec<T>;
728 let a: $0A<Self::Assoc>;
729 }
730}
731"#,
732 r#"
733trait Tra { type Assoc; fn a(); }
734struct Str {}
735impl Tra for Str {
736 type Assoc = u32;
737 fn a() {
738 type A<T> = Vec<T>;
739 let a: Vec<Self::Assoc>;
740 }
741}
742"#,
743 );
744 }
745
746 #[test]
747 fn param_default_associated_type() {
748 check_assist(
749 inline_type_alias,
750 r#"
751trait Tra { type Assoc; fn a() }
752struct Str {}
753impl Tra for Str {
754 type Assoc = u32;
755 fn a() {
756 type A<T = Self::Assoc> = Vec<T>;
757 let a: $0A;
758 }
759}
760"#,
761 r#"
762trait Tra { type Assoc; fn a() }
763struct Str {}
764impl Tra for Str {
765 type Assoc = u32;
766 fn a() {
767 type A<T = Self::Assoc> = Vec<T>;
768 let a: Vec<Self::Assoc>;
769 }
770}
771"#,
772 );
773 }
774
775 #[test]
776 fn function_pointer() {
777 check_assist(
778 inline_type_alias,
779 r#"
780type A = fn(u32);
781fn foo(a: u32) {}
782fn main() {
783 let a: $0A = foo;
784}
785"#,
786 r#"
787type A = fn(u32);
788fn foo(a: u32) {}
789fn main() {
790 let a: fn(u32) = foo;
791}
792"#,
793 );
794 }
795
796 #[test]
797 fn closure() {
798 check_assist(
799 inline_type_alias,
800 r#"
801type A = Box<dyn FnOnce(u32) -> u32>;
802fn main() {
803 let a: $0A = Box::new(|_| 0);
804}
805"#,
806 r#"
807type A = Box<dyn FnOnce(u32) -> u32>;
808fn main() {
809 let a: Box<dyn FnOnce(u32) -> u32> = Box::new(|_| 0);
810}
811"#,
812 );
813 }
814
815 #[test]
818 fn bounds() {
819 check_assist(
820 inline_type_alias,
821 r#"type A = std::io::Write; fn f<T>() where T: $0A {}"#,
822 r#"type A = std::io::Write; fn f<T>() where T: std::io::Write {}"#,
823 );
824 }
825
826 #[test]
827 fn function_parameter() {
828 check_assist(
829 inline_type_alias,
830 r#"
831type A = std::io::Write;
832fn f(a: impl $0A) {}
833"#,
834 r#"
835type A = std::io::Write;
836fn f(a: impl std::io::Write) {}
837"#,
838 );
839 }
840
841 #[test]
842 fn arg_expression() {
843 check_assist(
844 inline_type_alias,
845 r#"
846type A<const N: usize> = [u32; N];
847fn main() {
848 let a: $0A<{ 1 + 1 }>;
849}
850"#,
851 r#"
852type A<const N: usize> = [u32; N];
853fn main() {
854 let a: [u32; { 1 + 1 }];
855}
856"#,
857 )
858 }
859
860 #[test]
861 fn alias_instance_generic_path() {
862 check_assist(
863 inline_type_alias,
864 r#"
865type A<const N: usize> = [u32; N];
866fn main() {
867 let a: $0A<u32::MAX>;
868}
869"#,
870 r#"
871type A<const N: usize> = [u32; N];
872fn main() {
873 let a: [u32; u32::MAX];
874}
875"#,
876 )
877 }
878
879 #[test]
880 fn generic_type() {
881 check_assist(
882 inline_type_alias,
883 r#"
884type A = String;
885fn f(a: Vec<$0A>) {}
886"#,
887 r#"
888type A = String;
889fn f(a: Vec<String>) {}
890"#,
891 );
892 }
893
894 #[test]
895 fn missing_replacement_param() {
896 cov_mark::check!(missing_replacement_param);
897 check_assist_not_applicable(
898 inline_type_alias,
899 r#"
900type A<U> = Vec<T>;
901fn main() {
902 let a: $0A;
903}
904"#,
905 );
906 }
907
908 #[test]
909 fn full_path_type_is_replaced() {
910 check_assist(
911 inline_type_alias,
912 r#"
913mod foo {
914 pub type A = String;
915}
916fn main() {
917 let a: foo::$0A;
918}
919"#,
920 r#"
921mod foo {
922 pub type A = String;
923}
924fn main() {
925 let a: String;
926}
927"#,
928 );
929 }
930
931 #[test]
932 fn inline_self_type() {
933 check_assist(
934 inline_type_alias,
935 r#"
936struct Strukt;
937
938impl Strukt {
939 fn new() -> Self$0 {}
940}
941"#,
942 r#"
943struct Strukt;
944
945impl Strukt {
946 fn new() -> Strukt {}
947}
948"#,
949 );
950 check_assist(
951 inline_type_alias,
952 r#"
953struct Strukt<'a, T, const C: usize>(&'a [T; C]);
954
955impl<T, const C: usize> Strukt<'_, T, C> {
956 fn new() -> Self$0 {}
957}
958"#,
959 r#"
960struct Strukt<'a, T, const C: usize>(&'a [T; C]);
961
962impl<T, const C: usize> Strukt<'_, T, C> {
963 fn new() -> Strukt<'_, T, C> {}
964}
965"#,
966 );
967 check_assist(
968 inline_type_alias,
969 r#"
970struct Strukt<'a, T, const C: usize>(&'a [T; C]);
971
972trait Tr<'b, T> {}
973
974impl<T, const C: usize> Tr<'static, u8> for Strukt<'_, T, C> {
975 fn new() -> Self$0 {}
976}
977"#,
978 r#"
979struct Strukt<'a, T, const C: usize>(&'a [T; C]);
980
981trait Tr<'b, T> {}
982
983impl<T, const C: usize> Tr<'static, u8> for Strukt<'_, T, C> {
984 fn new() -> Strukt<'_, T, C> {}
985}
986"#,
987 );
988
989 check_assist_not_applicable(
990 inline_type_alias,
991 r#"
992trait Tr {
993 fn new() -> Self$0;
994}
995"#,
996 );
997 }
998
999 #[test]
1000 fn inline_types_with_lifetime() {
1001 check_assist(
1002 inline_type_alias_uses,
1003 r#"
1004struct A<'a, 'b>(pub &'a mut &'b mut ());
1005
1006type $0T<'a, 'b> = A<'a, 'b>;
1007
1008fn foo(_: T) {}
1009"#,
1010 r#"
1011struct A<'a, 'b>(pub &'a mut &'b mut ());
1012
1013
1014
1015fn foo(_: A) {}
1016"#,
1017 );
1018 }
1019
1020 #[test]
1021 fn mixed_lifetime_and_type_args() {
1022 check_assist(
1023 inline_type_alias,
1024 r#"
1025type Foo<'a, T> = Bar<'a, T>;
1026struct Bar<'a, T>(&'a T);
1027fn main() {
1028 let a: $0Foo<u32>;
1029}
1030"#,
1031 r#"
1032type Foo<'a, T> = Bar<'a, T>;
1033struct Bar<'a, T>(&'a T);
1034fn main() {
1035 let a: Bar<u32>;
1036}
1037"#,
1038 );
1039 }
1040
1041 mod inline_type_alias_uses {
1042 use crate::{handlers::inline_type_alias::inline_type_alias_uses, tests::check_assist};
1043
1044 #[test]
1045 fn inline_uses() {
1046 check_assist(
1047 inline_type_alias_uses,
1048 r#"
1049type $0A = u32;
1050
1051fn foo() {
1052 let _: A = 3;
1053 let _: A = 4;
1054}
1055"#,
1056 r#"
1057
1058
1059fn foo() {
1060 let _: u32 = 3;
1061 let _: u32 = 4;
1062}
1063"#,
1064 );
1065 }
1066
1067 #[test]
1068 fn inline_uses_across_files() {
1069 check_assist(
1070 inline_type_alias_uses,
1071 r#"
1072//- /lib.rs
1073mod foo;
1074type $0T<E> = Vec<E>;
1075fn f() -> T<&str> {
1076 vec!["hello"]
1077}
1078
1079//- /foo.rs
1080use super::T;
1081fn foo() {
1082 let _: T<i8> = Vec::new();
1083}
1084"#,
1085 r#"
1086//- /lib.rs
1087mod foo;
1088
1089fn f() -> Vec<&str> {
1090 vec!["hello"]
1091}
1092
1093//- /foo.rs
1094fn foo() {
1095 let _: Vec<i8> = Vec::new();
1096}
1097"#,
1098 );
1099 }
1100
1101 #[test]
1102 fn inline_uses_across_files_2() {
1103 check_assist(
1104 inline_type_alias_uses,
1105 r#"
1106//- /lib.rs
1107mod foo;
1108type $0I = i32;
1109
1110//- /foo.rs
1111use super::I;
1112fn foo() {
1113 let _: I = 0;
1114}
1115"#,
1116 r#"
1117//- /lib.rs
1118mod foo;
1119
1120
1121//- /foo.rs
1122fn foo() {
1123 let _: i32 = 0;
1124}
1125"#,
1126 );
1127 }
1128 }
1129}