1use 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
26pub(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 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
112pub(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 _ => 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 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
279fn 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 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 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 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 #[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 #[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 #[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}