aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_ide
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_ide')
-rw-r--r--crates/ra_ide/src/completion/complete_qualified_path.rs273
1 files changed, 262 insertions, 11 deletions
diff --git a/crates/ra_ide/src/completion/complete_qualified_path.rs b/crates/ra_ide/src/completion/complete_qualified_path.rs
index dd10f74e6..69e789a49 100644
--- a/crates/ra_ide/src/completion/complete_qualified_path.rs
+++ b/crates/ra_ide/src/completion/complete_qualified_path.rs
@@ -5,19 +5,30 @@ use ra_syntax::AstNode;
5use test_utils::tested_by; 5use test_utils::tested_by;
6 6
7use crate::completion::{CompletionContext, Completions}; 7use crate::completion::{CompletionContext, Completions};
8use rustc_hash::FxHashSet;
8 9
9pub(super) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionContext) { 10pub(super) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionContext) {
10 let path = match &ctx.path_prefix { 11 let path = match &ctx.path_prefix {
11 Some(path) => path.clone(), 12 Some(path) => path.clone(),
12 _ => return, 13 _ => return,
13 }; 14 };
14 let def = match ctx.scope().resolve_hir_path(&path) { 15 let scope = ctx.scope();
15 Some(PathResolution::Def(def)) => def, 16 let context_module = scope.module();
16 _ => return, 17
18 let res = if let Some(res) = scope.resolve_hir_path(&path) {
19 res
20 } else {
21 return;
17 }; 22 };
18 let context_module = ctx.scope().module(); 23
19 match def { 24 // Add associated types on type parameters and `Self`.
20 hir::ModuleDef::Module(module) => { 25 res.assoc_type_shorthand_candidates(ctx.db, |alias| {
26 acc.add_type_alias(ctx, alias);
27 None::<()>
28 });
29
30 match res {
31 PathResolution::Def(hir::ModuleDef::Module(module)) => {
21 let module_scope = module.scope(ctx.db, context_module); 32 let module_scope = module.scope(ctx.db, context_module);
22 for (name, def) in module_scope { 33 for (name, def) in module_scope {
23 if ctx.use_item_syntax.is_some() { 34 if ctx.use_item_syntax.is_some() {
@@ -35,7 +46,8 @@ pub(super) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon
35 acc.add_resolution(ctx, name.to_string(), &def); 46 acc.add_resolution(ctx, name.to_string(), &def);
36 } 47 }
37 } 48 }
38 hir::ModuleDef::Adt(_) | hir::ModuleDef::TypeAlias(_) => { 49 PathResolution::Def(def @ hir::ModuleDef::Adt(_))
50 | PathResolution::Def(def @ hir::ModuleDef::TypeAlias(_)) => {
39 if let hir::ModuleDef::Adt(Adt::Enum(e)) = def { 51 if let hir::ModuleDef::Adt(Adt::Enum(e)) = def {
40 for variant in e.variants(ctx.db) { 52 for variant in e.variants(ctx.db) {
41 acc.add_enum_variant(ctx, variant, None); 53 acc.add_enum_variant(ctx, variant, None);
@@ -46,8 +58,10 @@ pub(super) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon
46 hir::ModuleDef::TypeAlias(a) => a.ty(ctx.db), 58 hir::ModuleDef::TypeAlias(a) => a.ty(ctx.db),
47 _ => unreachable!(), 59 _ => unreachable!(),
48 }; 60 };
49 // Iterate assoc types separately 61
50 // FIXME: complete T::AssocType 62 // XXX: For parity with Rust bug #22519, this does not complete Ty::AssocType.
63 // (where AssocType is defined on a trait, not an inherent impl)
64
51 let krate = ctx.krate; 65 let krate = ctx.krate;
52 if let Some(krate) = krate { 66 if let Some(krate) = krate {
53 let traits_in_scope = ctx.scope().traits_in_scope(); 67 let traits_in_scope = ctx.scope().traits_in_scope();
@@ -65,6 +79,7 @@ pub(super) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon
65 None::<()> 79 None::<()>
66 }); 80 });
67 81
82 // Iterate assoc types separately
68 ty.iterate_impl_items(ctx.db, krate, |item| { 83 ty.iterate_impl_items(ctx.db, krate, |item| {
69 if context_module.map_or(false, |m| !item.is_visible_from(ctx.db, m)) { 84 if context_module.map_or(false, |m| !item.is_visible_from(ctx.db, m)) {
70 return None; 85 return None;
@@ -77,7 +92,8 @@ pub(super) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon
77 }); 92 });
78 } 93 }
79 } 94 }
80 hir::ModuleDef::Trait(t) => { 95 PathResolution::Def(hir::ModuleDef::Trait(t)) => {
96 // Handles `Trait::assoc` as well as `<Ty as Trait>::assoc`.
81 for item in t.items(ctx.db) { 97 for item in t.items(ctx.db) {
82 if context_module.map_or(false, |m| !item.is_visible_from(ctx.db, m)) { 98 if context_module.map_or(false, |m| !item.is_visible_from(ctx.db, m)) {
83 continue; 99 continue;
@@ -91,8 +107,38 @@ pub(super) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon
91 } 107 }
92 } 108 }
93 } 109 }
110 PathResolution::TypeParam(_) | PathResolution::SelfType(_) => {
111 if let Some(krate) = ctx.krate {
112 let ty = match res {
113 PathResolution::TypeParam(param) => param.ty(ctx.db),
114 PathResolution::SelfType(impl_def) => impl_def.target_ty(ctx.db),
115 _ => return,
116 };
117
118 let traits_in_scope = ctx.scope().traits_in_scope();
119 let mut seen = FxHashSet::default();
120 ty.iterate_path_candidates(ctx.db, krate, &traits_in_scope, None, |_ty, item| {
121 if context_module.map_or(false, |m| !item.is_visible_from(ctx.db, m)) {
122 return None;
123 }
124
125 // We might iterate candidates of a trait multiple times here, so deduplicate
126 // them.
127 if seen.insert(item) {
128 match item {
129 hir::AssocItem::Function(func) => {
130 acc.add_function(ctx, func, None);
131 }
132 hir::AssocItem::Const(ct) => acc.add_const(ctx, ct),
133 hir::AssocItem::TypeAlias(ty) => acc.add_type_alias(ctx, ty),
134 }
135 }
136 None::<()>
137 });
138 }
139 }
94 _ => {} 140 _ => {}
95 }; 141 }
96} 142}
97 143
98#[cfg(test)] 144#[cfg(test)]
@@ -844,6 +890,211 @@ mod tests {
844 } 890 }
845 891
846 #[test] 892 #[test]
893 fn completes_ty_param_assoc_ty() {
894 assert_debug_snapshot!(
895 do_reference_completion(
896 "
897 //- /lib.rs
898 trait Super {
899 type Ty;
900 const CONST: u8;
901 fn func() {}
902 fn method(&self) {}
903 }
904
905 trait Sub: Super {
906 type SubTy;
907 const C2: ();
908 fn subfunc() {}
909 fn submethod(&self) {}
910 }
911
912 fn foo<T: Sub>() {
913 T::<|>
914 }
915 "
916 ),
917 @r###"
918 [
919 CompletionItem {
920 label: "C2",
921 source_range: 219..219,
922 delete: 219..219,
923 insert: "C2",
924 kind: Const,
925 detail: "const C2: ();",
926 },
927 CompletionItem {
928 label: "CONST",
929 source_range: 219..219,
930 delete: 219..219,
931 insert: "CONST",
932 kind: Const,
933 detail: "const CONST: u8;",
934 },
935 CompletionItem {
936 label: "SubTy",
937 source_range: 219..219,
938 delete: 219..219,
939 insert: "SubTy",
940 kind: TypeAlias,
941 detail: "type SubTy;",
942 },
943 CompletionItem {
944 label: "Ty",
945 source_range: 219..219,
946 delete: 219..219,
947 insert: "Ty",
948 kind: TypeAlias,
949 detail: "type Ty;",
950 },
951 CompletionItem {
952 label: "func()",
953 source_range: 219..219,
954 delete: 219..219,
955 insert: "func()$0",
956 kind: Function,
957 lookup: "func",
958 detail: "fn func()",
959 },
960 CompletionItem {
961 label: "method()",
962 source_range: 219..219,
963 delete: 219..219,
964 insert: "method()$0",
965 kind: Method,
966 lookup: "method",
967 detail: "fn method(&self)",
968 },
969 CompletionItem {
970 label: "subfunc()",
971 source_range: 219..219,
972 delete: 219..219,
973 insert: "subfunc()$0",
974 kind: Function,
975 lookup: "subfunc",
976 detail: "fn subfunc()",
977 },
978 CompletionItem {
979 label: "submethod()",
980 source_range: 219..219,
981 delete: 219..219,
982 insert: "submethod()$0",
983 kind: Method,
984 lookup: "submethod",
985 detail: "fn submethod(&self)",
986 },
987 ]
988 "###
989 );
990 }
991
992 #[test]
993 fn completes_self_param_assoc_ty() {
994 assert_debug_snapshot!(
995 do_reference_completion(
996 "
997 //- /lib.rs
998 trait Super {
999 type Ty;
1000 const CONST: u8 = 0;
1001 fn func() {}
1002 fn method(&self) {}
1003 }
1004
1005 trait Sub: Super {
1006 type SubTy;
1007 const C2: () = ();
1008 fn subfunc() {}
1009 fn submethod(&self) {}
1010 }
1011
1012 struct Wrap<T>(T);
1013 impl<T> Super for Wrap<T> {}
1014 impl<T> Sub for Wrap<T> {
1015 fn subfunc() {
1016 // Should be able to assume `Self: Sub + Super`
1017 Self::<|>
1018 }
1019 }
1020 "
1021 ),
1022 @r###"
1023 [
1024 CompletionItem {
1025 label: "C2",
1026 source_range: 365..365,
1027 delete: 365..365,
1028 insert: "C2",
1029 kind: Const,
1030 detail: "const C2: () = ();",
1031 },
1032 CompletionItem {
1033 label: "CONST",
1034 source_range: 365..365,
1035 delete: 365..365,
1036 insert: "CONST",
1037 kind: Const,
1038 detail: "const CONST: u8 = 0;",
1039 },
1040 CompletionItem {
1041 label: "SubTy",
1042 source_range: 365..365,
1043 delete: 365..365,
1044 insert: "SubTy",
1045 kind: TypeAlias,
1046 detail: "type SubTy;",
1047 },
1048 CompletionItem {
1049 label: "Ty",
1050 source_range: 365..365,
1051 delete: 365..365,
1052 insert: "Ty",
1053 kind: TypeAlias,
1054 detail: "type Ty;",
1055 },
1056 CompletionItem {
1057 label: "func()",
1058 source_range: 365..365,
1059 delete: 365..365,
1060 insert: "func()$0",
1061 kind: Function,
1062 lookup: "func",
1063 detail: "fn func()",
1064 },
1065 CompletionItem {
1066 label: "method()",
1067 source_range: 365..365,
1068 delete: 365..365,
1069 insert: "method()$0",
1070 kind: Method,
1071 lookup: "method",
1072 detail: "fn method(&self)",
1073 },
1074 CompletionItem {
1075 label: "subfunc()",
1076 source_range: 365..365,
1077 delete: 365..365,
1078 insert: "subfunc()$0",
1079 kind: Function,
1080 lookup: "subfunc",
1081 detail: "fn subfunc()",
1082 },
1083 CompletionItem {
1084 label: "submethod()",
1085 source_range: 365..365,
1086 delete: 365..365,
1087 insert: "submethod()$0",
1088 kind: Method,
1089 lookup: "submethod",
1090 detail: "fn submethod(&self)",
1091 },
1092 ]
1093 "###
1094 );
1095 }
1096
1097 #[test]
847 fn completes_type_alias() { 1098 fn completes_type_alias() {
848 assert_debug_snapshot!( 1099 assert_debug_snapshot!(
849 do_reference_completion( 1100 do_reference_completion(