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