diff options
-rw-r--r-- | crates/ra_hir/src/code_model.rs | 52 | ||||
-rw-r--r-- | crates/ra_hir_def/src/data.rs | 41 | ||||
-rw-r--r-- | crates/ra_ide/src/completion/complete_dot.rs | 38 | ||||
-rw-r--r-- | crates/ra_ide/src/completion/complete_path.rs | 105 |
4 files changed, 217 insertions, 19 deletions
diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs index 2944926e6..911c809fd 100644 --- a/crates/ra_hir/src/code_model.rs +++ b/crates/ra_hir/src/code_model.rs | |||
@@ -204,10 +204,26 @@ impl Module { | |||
204 | } | 204 | } |
205 | 205 | ||
206 | /// Returns a `ModuleScope`: a set of items, visible in this module. | 206 | /// Returns a `ModuleScope`: a set of items, visible in this module. |
207 | pub fn scope(self, db: &impl HirDatabase) -> Vec<(Name, ScopeDef)> { | 207 | pub fn scope( |
208 | self, | ||
209 | db: &impl HirDatabase, | ||
210 | visible_from: Option<Module>, | ||
211 | ) -> Vec<(Name, ScopeDef)> { | ||
208 | db.crate_def_map(self.id.krate)[self.id.local_id] | 212 | db.crate_def_map(self.id.krate)[self.id.local_id] |
209 | .scope | 213 | .scope |
210 | .entries() | 214 | .entries() |
215 | .filter_map(|(name, def)| { | ||
216 | if let Some(m) = visible_from { | ||
217 | let filtered = def.filter_visibility(|vis| vis.is_visible_from(db, m.id)); | ||
218 | if filtered.is_none() && !def.is_none() { | ||
219 | None | ||
220 | } else { | ||
221 | Some((name, filtered)) | ||
222 | } | ||
223 | } else { | ||
224 | Some((name, def)) | ||
225 | } | ||
226 | }) | ||
211 | .map(|(name, def)| (name.clone(), def.into())) | 227 | .map(|(name, def)| (name.clone(), def.into())) |
212 | .collect() | 228 | .collect() |
213 | } | 229 | } |
@@ -571,6 +587,14 @@ impl Function { | |||
571 | } | 587 | } |
572 | } | 588 | } |
573 | 589 | ||
590 | impl HasVisibility for Function { | ||
591 | fn visibility(&self, db: &impl HirDatabase) -> Visibility { | ||
592 | let function_data = db.function_data(self.id); | ||
593 | let visibility = &function_data.visibility; | ||
594 | visibility.resolve(db, &self.id.resolver(db)) | ||
595 | } | ||
596 | } | ||
597 | |||
574 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | 598 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
575 | pub struct Const { | 599 | pub struct Const { |
576 | pub(crate) id: ConstId, | 600 | pub(crate) id: ConstId, |
@@ -590,6 +614,14 @@ impl Const { | |||
590 | } | 614 | } |
591 | } | 615 | } |
592 | 616 | ||
617 | impl HasVisibility for Const { | ||
618 | fn visibility(&self, db: &impl HirDatabase) -> Visibility { | ||
619 | let function_data = db.const_data(self.id); | ||
620 | let visibility = &function_data.visibility; | ||
621 | visibility.resolve(db, &self.id.resolver(db)) | ||
622 | } | ||
623 | } | ||
624 | |||
593 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | 625 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
594 | pub struct Static { | 626 | pub struct Static { |
595 | pub(crate) id: StaticId, | 627 | pub(crate) id: StaticId, |
@@ -664,6 +696,14 @@ impl TypeAlias { | |||
664 | } | 696 | } |
665 | } | 697 | } |
666 | 698 | ||
699 | impl HasVisibility for TypeAlias { | ||
700 | fn visibility(&self, db: &impl HirDatabase) -> Visibility { | ||
701 | let function_data = db.type_alias_data(self.id); | ||
702 | let visibility = &function_data.visibility; | ||
703 | visibility.resolve(db, &self.id.resolver(db)) | ||
704 | } | ||
705 | } | ||
706 | |||
667 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | 707 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
668 | pub struct MacroDef { | 708 | pub struct MacroDef { |
669 | pub(crate) id: MacroDefId, | 709 | pub(crate) id: MacroDefId, |
@@ -751,6 +791,16 @@ impl AssocItem { | |||
751 | } | 791 | } |
752 | } | 792 | } |
753 | 793 | ||
794 | impl HasVisibility for AssocItem { | ||
795 | fn visibility(&self, db: &impl HirDatabase) -> Visibility { | ||
796 | match self { | ||
797 | AssocItem::Function(f) => f.visibility(db), | ||
798 | AssocItem::Const(c) => c.visibility(db), | ||
799 | AssocItem::TypeAlias(t) => t.visibility(db), | ||
800 | } | ||
801 | } | ||
802 | } | ||
803 | |||
754 | #[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)] | 804 | #[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)] |
755 | pub enum GenericDef { | 805 | pub enum GenericDef { |
756 | Function(Function), | 806 | Function(Function), |
diff --git a/crates/ra_hir_def/src/data.rs b/crates/ra_hir_def/src/data.rs index 9fc43f3fb..a72eb5369 100644 --- a/crates/ra_hir_def/src/data.rs +++ b/crates/ra_hir_def/src/data.rs | |||
@@ -7,13 +7,16 @@ use hir_expand::{ | |||
7 | AstId, InFile, | 7 | AstId, InFile, |
8 | }; | 8 | }; |
9 | use ra_prof::profile; | 9 | use ra_prof::profile; |
10 | use ra_syntax::ast::{self, AstNode, ImplItem, ModuleItemOwner, NameOwner, TypeAscriptionOwner}; | 10 | use ra_syntax::ast::{ |
11 | self, AstNode, ImplItem, ModuleItemOwner, NameOwner, TypeAscriptionOwner, VisibilityOwner, | ||
12 | }; | ||
11 | 13 | ||
12 | use crate::{ | 14 | use crate::{ |
13 | db::DefDatabase, | 15 | db::DefDatabase, |
14 | path::{path, GenericArgs, Path}, | 16 | path::{path, GenericArgs, Path}, |
15 | src::HasSource, | 17 | src::HasSource, |
16 | type_ref::{Mutability, TypeBound, TypeRef}, | 18 | type_ref::{Mutability, TypeBound, TypeRef}, |
19 | visibility::RawVisibility, | ||
17 | AssocContainerId, AssocItemId, ConstId, ConstLoc, Expander, FunctionId, FunctionLoc, HasModule, | 20 | AssocContainerId, AssocItemId, ConstId, ConstLoc, Expander, FunctionId, FunctionLoc, HasModule, |
18 | ImplId, Intern, Lookup, ModuleId, StaticId, TraitId, TypeAliasId, TypeAliasLoc, | 21 | ImplId, Intern, Lookup, ModuleId, StaticId, TraitId, TypeAliasId, TypeAliasLoc, |
19 | }; | 22 | }; |
@@ -26,6 +29,7 @@ pub struct FunctionData { | |||
26 | /// True if the first param is `self`. This is relevant to decide whether this | 29 | /// True if the first param is `self`. This is relevant to decide whether this |
27 | /// can be called as a method. | 30 | /// can be called as a method. |
28 | pub has_self_param: bool, | 31 | pub has_self_param: bool, |
32 | pub visibility: RawVisibility, | ||
29 | } | 33 | } |
30 | 34 | ||
31 | impl FunctionData { | 35 | impl FunctionData { |
@@ -72,7 +76,9 @@ impl FunctionData { | |||
72 | ret_type | 76 | ret_type |
73 | }; | 77 | }; |
74 | 78 | ||
75 | let sig = FunctionData { name, params, ret_type, has_self_param }; | 79 | let visibility = RawVisibility::from_ast(db, src.map(|s| s.visibility())); |
80 | |||
81 | let sig = FunctionData { name, params, ret_type, has_self_param, visibility }; | ||
76 | Arc::new(sig) | 82 | Arc::new(sig) |
77 | } | 83 | } |
78 | } | 84 | } |
@@ -91,6 +97,7 @@ fn desugar_future_path(orig: TypeRef) -> Path { | |||
91 | pub struct TypeAliasData { | 97 | pub struct TypeAliasData { |
92 | pub name: Name, | 98 | pub name: Name, |
93 | pub type_ref: Option<TypeRef>, | 99 | pub type_ref: Option<TypeRef>, |
100 | pub visibility: RawVisibility, | ||
94 | } | 101 | } |
95 | 102 | ||
96 | impl TypeAliasData { | 103 | impl TypeAliasData { |
@@ -98,10 +105,11 @@ impl TypeAliasData { | |||
98 | db: &impl DefDatabase, | 105 | db: &impl DefDatabase, |
99 | typ: TypeAliasId, | 106 | typ: TypeAliasId, |
100 | ) -> Arc<TypeAliasData> { | 107 | ) -> Arc<TypeAliasData> { |
101 | let node = typ.lookup(db).source(db).value; | 108 | let node = typ.lookup(db).source(db); |
102 | let name = node.name().map_or_else(Name::missing, |n| n.as_name()); | 109 | let name = node.value.name().map_or_else(Name::missing, |n| n.as_name()); |
103 | let type_ref = node.type_ref().map(TypeRef::from_ast); | 110 | let type_ref = node.value.type_ref().map(TypeRef::from_ast); |
104 | Arc::new(TypeAliasData { name, type_ref }) | 111 | let visibility = RawVisibility::from_ast(db, node.map(|n| n.visibility())); |
112 | Arc::new(TypeAliasData { name, type_ref, visibility }) | ||
105 | } | 113 | } |
106 | } | 114 | } |
107 | 115 | ||
@@ -217,23 +225,28 @@ pub struct ConstData { | |||
217 | /// const _: () = (); | 225 | /// const _: () = (); |
218 | pub name: Option<Name>, | 226 | pub name: Option<Name>, |
219 | pub type_ref: TypeRef, | 227 | pub type_ref: TypeRef, |
228 | pub visibility: RawVisibility, | ||
220 | } | 229 | } |
221 | 230 | ||
222 | impl ConstData { | 231 | impl ConstData { |
223 | pub(crate) fn const_data_query(db: &impl DefDatabase, konst: ConstId) -> Arc<ConstData> { | 232 | pub(crate) fn const_data_query(db: &impl DefDatabase, konst: ConstId) -> Arc<ConstData> { |
224 | let node = konst.lookup(db).source(db).value; | 233 | let node = konst.lookup(db).source(db); |
225 | Arc::new(ConstData::new(&node)) | 234 | Arc::new(ConstData::new(db, node)) |
226 | } | 235 | } |
227 | 236 | ||
228 | pub(crate) fn static_data_query(db: &impl DefDatabase, konst: StaticId) -> Arc<ConstData> { | 237 | pub(crate) fn static_data_query(db: &impl DefDatabase, konst: StaticId) -> Arc<ConstData> { |
229 | let node = konst.lookup(db).source(db).value; | 238 | let node = konst.lookup(db).source(db); |
230 | Arc::new(ConstData::new(&node)) | 239 | Arc::new(ConstData::new(db, node)) |
231 | } | 240 | } |
232 | 241 | ||
233 | fn new<N: NameOwner + TypeAscriptionOwner>(node: &N) -> ConstData { | 242 | fn new<N: NameOwner + TypeAscriptionOwner + VisibilityOwner>( |
234 | let name = node.name().map(|n| n.as_name()); | 243 | db: &impl DefDatabase, |
235 | let type_ref = TypeRef::from_ast_opt(node.ascribed_type()); | 244 | node: InFile<N>, |
236 | ConstData { name, type_ref } | 245 | ) -> ConstData { |
246 | let name = node.value.name().map(|n| n.as_name()); | ||
247 | let type_ref = TypeRef::from_ast_opt(node.value.ascribed_type()); | ||
248 | let visibility = RawVisibility::from_ast(db, node.map(|n| n.visibility())); | ||
249 | ConstData { name, type_ref, visibility } | ||
237 | } | 250 | } |
238 | } | 251 | } |
239 | 252 | ||
diff --git a/crates/ra_ide/src/completion/complete_dot.rs b/crates/ra_ide/src/completion/complete_dot.rs index 9145aa183..acada48ae 100644 --- a/crates/ra_ide/src/completion/complete_dot.rs +++ b/crates/ra_ide/src/completion/complete_dot.rs | |||
@@ -57,7 +57,10 @@ fn complete_methods(acc: &mut Completions, ctx: &CompletionContext, receiver: &T | |||
57 | let mut seen_methods = FxHashSet::default(); | 57 | let mut seen_methods = FxHashSet::default(); |
58 | let traits_in_scope = ctx.scope().traits_in_scope(); | 58 | let traits_in_scope = ctx.scope().traits_in_scope(); |
59 | receiver.iterate_method_candidates(ctx.db, krate, &traits_in_scope, None, |_ty, func| { | 59 | receiver.iterate_method_candidates(ctx.db, krate, &traits_in_scope, None, |_ty, func| { |
60 | if func.has_self_param(ctx.db) && seen_methods.insert(func.name(ctx.db)) { | 60 | if func.has_self_param(ctx.db) |
61 | && ctx.scope().module().map_or(true, |m| func.is_visible_from(ctx.db, m)) | ||
62 | && seen_methods.insert(func.name(ctx.db)) | ||
63 | { | ||
61 | acc.add_function(ctx, func); | 64 | acc.add_function(ctx, func); |
62 | } | 65 | } |
63 | None::<()> | 66 | None::<()> |
@@ -308,6 +311,39 @@ mod tests { | |||
308 | } | 311 | } |
309 | 312 | ||
310 | #[test] | 313 | #[test] |
314 | fn test_method_completion_private() { | ||
315 | assert_debug_snapshot!( | ||
316 | do_ref_completion( | ||
317 | r" | ||
318 | struct A {} | ||
319 | mod m { | ||
320 | impl super::A { | ||
321 | fn private_method(&self) {} | ||
322 | pub(super) fn the_method(&self) {} | ||
323 | } | ||
324 | } | ||
325 | fn foo(a: A) { | ||
326 | a.<|> | ||
327 | } | ||
328 | ", | ||
329 | ), | ||
330 | @r###" | ||
331 | [ | ||
332 | CompletionItem { | ||
333 | label: "the_method()", | ||
334 | source_range: [256; 256), | ||
335 | delete: [256; 256), | ||
336 | insert: "the_method()$0", | ||
337 | kind: Method, | ||
338 | lookup: "the_method", | ||
339 | detail: "pub(super) fn the_method(&self)", | ||
340 | }, | ||
341 | ] | ||
342 | "### | ||
343 | ); | ||
344 | } | ||
345 | |||
346 | #[test] | ||
311 | fn test_trait_method_completion() { | 347 | fn test_trait_method_completion() { |
312 | assert_debug_snapshot!( | 348 | assert_debug_snapshot!( |
313 | do_ref_completion( | 349 | do_ref_completion( |
diff --git a/crates/ra_ide/src/completion/complete_path.rs b/crates/ra_ide/src/completion/complete_path.rs index 1a9699466..d2c758571 100644 --- a/crates/ra_ide/src/completion/complete_path.rs +++ b/crates/ra_ide/src/completion/complete_path.rs | |||
@@ -1,6 +1,6 @@ | |||
1 | //! Completion of paths, including when writing a single name. | 1 | //! Completion of paths, including when writing a single name. |
2 | 2 | ||
3 | use hir::{Adt, PathResolution, ScopeDef}; | 3 | use hir::{Adt, HasVisibility, PathResolution, ScopeDef}; |
4 | use ra_syntax::AstNode; | 4 | use ra_syntax::AstNode; |
5 | use test_utils::tested_by; | 5 | use test_utils::tested_by; |
6 | 6 | ||
@@ -15,9 +15,10 @@ pub(super) fn complete_path(acc: &mut Completions, ctx: &CompletionContext) { | |||
15 | Some(PathResolution::Def(def)) => def, | 15 | Some(PathResolution::Def(def)) => def, |
16 | _ => return, | 16 | _ => return, |
17 | }; | 17 | }; |
18 | let context_module = ctx.scope().module(); | ||
18 | match def { | 19 | match def { |
19 | hir::ModuleDef::Module(module) => { | 20 | hir::ModuleDef::Module(module) => { |
20 | let module_scope = module.scope(ctx.db); | 21 | let module_scope = module.scope(ctx.db, context_module); |
21 | for (name, def) in module_scope { | 22 | for (name, def) in module_scope { |
22 | if ctx.use_item_syntax.is_some() { | 23 | if ctx.use_item_syntax.is_some() { |
23 | if let ScopeDef::Unknown = def { | 24 | if let ScopeDef::Unknown = def { |
@@ -51,6 +52,9 @@ pub(super) fn complete_path(acc: &mut Completions, ctx: &CompletionContext) { | |||
51 | if let Some(krate) = krate { | 52 | if let Some(krate) = krate { |
52 | let traits_in_scope = ctx.scope().traits_in_scope(); | 53 | let traits_in_scope = ctx.scope().traits_in_scope(); |
53 | ty.iterate_path_candidates(ctx.db, krate, &traits_in_scope, None, |_ty, item| { | 54 | ty.iterate_path_candidates(ctx.db, krate, &traits_in_scope, None, |_ty, item| { |
55 | if context_module.map_or(false, |m| !item.is_visible_from(ctx.db, m)) { | ||
56 | return None; | ||
57 | } | ||
54 | match item { | 58 | match item { |
55 | hir::AssocItem::Function(func) => { | 59 | hir::AssocItem::Function(func) => { |
56 | if !func.has_self_param(ctx.db) { | 60 | if !func.has_self_param(ctx.db) { |
@@ -64,6 +68,9 @@ pub(super) fn complete_path(acc: &mut Completions, ctx: &CompletionContext) { | |||
64 | }); | 68 | }); |
65 | 69 | ||
66 | ty.iterate_impl_items(ctx.db, krate, |item| { | 70 | ty.iterate_impl_items(ctx.db, krate, |item| { |
71 | if context_module.map_or(false, |m| !item.is_visible_from(ctx.db, m)) { | ||
72 | return None; | ||
73 | } | ||
67 | match item { | 74 | match item { |
68 | hir::AssocItem::Function(_) | hir::AssocItem::Const(_) => {} | 75 | hir::AssocItem::Function(_) | hir::AssocItem::Const(_) => {} |
69 | hir::AssocItem::TypeAlias(ty) => acc.add_type_alias(ctx, ty), | 76 | hir::AssocItem::TypeAlias(ty) => acc.add_type_alias(ctx, ty), |
@@ -74,6 +81,9 @@ pub(super) fn complete_path(acc: &mut Completions, ctx: &CompletionContext) { | |||
74 | } | 81 | } |
75 | hir::ModuleDef::Trait(t) => { | 82 | hir::ModuleDef::Trait(t) => { |
76 | for item in t.items(ctx.db) { | 83 | for item in t.items(ctx.db) { |
84 | if context_module.map_or(false, |m| !item.is_visible_from(ctx.db, m)) { | ||
85 | continue; | ||
86 | } | ||
77 | match item { | 87 | match item { |
78 | hir::AssocItem::Function(func) => { | 88 | hir::AssocItem::Function(func) => { |
79 | if !func.has_self_param(ctx.db) { | 89 | if !func.has_self_param(ctx.db) { |
@@ -170,6 +180,41 @@ mod tests { | |||
170 | } | 180 | } |
171 | 181 | ||
172 | #[test] | 182 | #[test] |
183 | fn path_visibility() { | ||
184 | assert_debug_snapshot!( | ||
185 | do_reference_completion( | ||
186 | r" | ||
187 | use self::my::<|>; | ||
188 | |||
189 | mod my { | ||
190 | struct Bar; | ||
191 | pub struct Foo; | ||
192 | pub use Bar as PublicBar; | ||
193 | } | ||
194 | " | ||
195 | ), | ||
196 | @r###" | ||
197 | [ | ||
198 | CompletionItem { | ||
199 | label: "Foo", | ||
200 | source_range: [31; 31), | ||
201 | delete: [31; 31), | ||
202 | insert: "Foo", | ||
203 | kind: Struct, | ||
204 | }, | ||
205 | CompletionItem { | ||
206 | label: "PublicBar", | ||
207 | source_range: [31; 31), | ||
208 | delete: [31; 31), | ||
209 | insert: "PublicBar", | ||
210 | kind: Struct, | ||
211 | }, | ||
212 | ] | ||
213 | "### | ||
214 | ); | ||
215 | } | ||
216 | |||
217 | #[test] | ||
173 | fn completes_use_item_starting_with_self() { | 218 | fn completes_use_item_starting_with_self() { |
174 | assert_debug_snapshot!( | 219 | assert_debug_snapshot!( |
175 | do_reference_completion( | 220 | do_reference_completion( |
@@ -177,7 +222,7 @@ mod tests { | |||
177 | use self::m::<|>; | 222 | use self::m::<|>; |
178 | 223 | ||
179 | mod m { | 224 | mod m { |
180 | struct Bar; | 225 | pub struct Bar; |
181 | } | 226 | } |
182 | " | 227 | " |
183 | ), | 228 | ), |
@@ -502,6 +547,60 @@ mod tests { | |||
502 | } | 547 | } |
503 | 548 | ||
504 | #[test] | 549 | #[test] |
550 | fn associated_item_visibility() { | ||
551 | assert_debug_snapshot!( | ||
552 | do_reference_completion( | ||
553 | " | ||
554 | //- /lib.rs | ||
555 | struct S; | ||
556 | |||
557 | mod m { | ||
558 | impl super::S { | ||
559 | pub(super) fn public_method() { } | ||
560 | fn private_method() { } | ||
561 | pub(super) type PublicType = u32; | ||
562 | type PrivateType = u32; | ||
563 | pub(super) const PUBLIC_CONST: u32 = 1; | ||
564 | const PRIVATE_CONST: u32 = 1; | ||
565 | } | ||
566 | } | ||
567 | |||
568 | fn foo() { let _ = S::<|> } | ||
569 | " | ||
570 | ), | ||
571 | @r###" | ||
572 | [ | ||
573 | CompletionItem { | ||
574 | label: "PUBLIC_CONST", | ||
575 | source_range: [302; 302), | ||
576 | delete: [302; 302), | ||
577 | insert: "PUBLIC_CONST", | ||
578 | kind: Const, | ||
579 | detail: "pub(super) const PUBLIC_CONST: u32 = 1;", | ||
580 | }, | ||
581 | CompletionItem { | ||
582 | label: "PublicType", | ||
583 | source_range: [302; 302), | ||
584 | delete: [302; 302), | ||
585 | insert: "PublicType", | ||
586 | kind: TypeAlias, | ||
587 | detail: "pub(super) type PublicType = u32;", | ||
588 | }, | ||
589 | CompletionItem { | ||
590 | label: "public_method()", | ||
591 | source_range: [302; 302), | ||
592 | delete: [302; 302), | ||
593 | insert: "public_method()$0", | ||
594 | kind: Function, | ||
595 | lookup: "public_method", | ||
596 | detail: "pub(super) fn public_method()", | ||
597 | }, | ||
598 | ] | ||
599 | "### | ||
600 | ); | ||
601 | } | ||
602 | |||
603 | #[test] | ||
505 | fn completes_enum_associated_method() { | 604 | fn completes_enum_associated_method() { |
506 | assert_debug_snapshot!( | 605 | assert_debug_snapshot!( |
507 | do_reference_completion( | 606 | do_reference_completion( |