Handle visibility for assoc item path completion as well

This commit is contained in:
Florian Diebold 2020-03-08 15:11:57 +01:00
parent d9c77c5453
commit 05e1c7b197
3 changed files with 124 additions and 22 deletions

View file

@ -204,19 +204,25 @@ impl Module {
} }
/// Returns a `ModuleScope`: a set of items, visible in this module. /// Returns a `ModuleScope`: a set of items, visible in this module.
pub fn scope(self, db: &impl HirDatabase, visible_from: Option<Module>) -> Vec<(Name, ScopeDef)> { pub fn scope(
self,
db: &impl HirDatabase,
visible_from: Option<Module>,
) -> Vec<(Name, ScopeDef)> {
db.crate_def_map(self.id.krate)[self.id.local_id] db.crate_def_map(self.id.krate)[self.id.local_id]
.scope .scope
.entries() .entries()
.filter_map(|(name, def)| if let Some(m) = visible_from { .filter_map(|(name, def)| {
let filtered = def.filter_visibility(|vis| vis.is_visible_from(db, m.id)); if let Some(m) = visible_from {
if filtered.is_none() && !def.is_none() { let filtered = def.filter_visibility(|vis| vis.is_visible_from(db, m.id));
None if filtered.is_none() && !def.is_none() {
None
} else {
Some((name, filtered))
}
} else { } else {
Some((name, filtered)) Some((name, def))
} }
} else {
Some((name, def))
}) })
.map(|(name, def)| (name.clone(), def.into())) .map(|(name, def)| (name.clone(), def.into()))
.collect() .collect()
@ -608,6 +614,14 @@ impl Const {
} }
} }
impl HasVisibility for Const {
fn visibility(&self, db: &impl HirDatabase) -> Visibility {
let function_data = db.const_data(self.id);
let visibility = &function_data.visibility;
visibility.resolve(db, &self.id.resolver(db))
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct Static { pub struct Static {
pub(crate) id: StaticId, pub(crate) id: StaticId,
@ -682,6 +696,14 @@ impl TypeAlias {
} }
} }
impl HasVisibility for TypeAlias {
fn visibility(&self, db: &impl HirDatabase) -> Visibility {
let function_data = db.type_alias_data(self.id);
let visibility = &function_data.visibility;
visibility.resolve(db, &self.id.resolver(db))
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct MacroDef { pub struct MacroDef {
pub(crate) id: MacroDefId, pub(crate) id: MacroDefId,
@ -769,6 +791,16 @@ impl AssocItem {
} }
} }
impl HasVisibility for AssocItem {
fn visibility(&self, db: &impl HirDatabase) -> Visibility {
match self {
AssocItem::Function(f) => f.visibility(db),
AssocItem::Const(c) => c.visibility(db),
AssocItem::TypeAlias(t) => t.visibility(db),
}
}
}
#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)] #[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
pub enum GenericDef { pub enum GenericDef {
Function(Function), Function(Function),

View file

@ -97,6 +97,7 @@ fn desugar_future_path(orig: TypeRef) -> Path {
pub struct TypeAliasData { pub struct TypeAliasData {
pub name: Name, pub name: Name,
pub type_ref: Option<TypeRef>, pub type_ref: Option<TypeRef>,
pub visibility: RawVisibility,
} }
impl TypeAliasData { impl TypeAliasData {
@ -104,10 +105,11 @@ impl TypeAliasData {
db: &impl DefDatabase, db: &impl DefDatabase,
typ: TypeAliasId, typ: TypeAliasId,
) -> Arc<TypeAliasData> { ) -> Arc<TypeAliasData> {
let node = typ.lookup(db).source(db).value; let node = typ.lookup(db).source(db);
let name = node.name().map_or_else(Name::missing, |n| n.as_name()); let name = node.value.name().map_or_else(Name::missing, |n| n.as_name());
let type_ref = node.type_ref().map(TypeRef::from_ast); let type_ref = node.value.type_ref().map(TypeRef::from_ast);
Arc::new(TypeAliasData { name, type_ref }) let visibility = RawVisibility::from_ast(db, node.map(|n| n.visibility()));
Arc::new(TypeAliasData { name, type_ref, visibility })
} }
} }
@ -223,23 +225,28 @@ pub struct ConstData {
/// const _: () = (); /// const _: () = ();
pub name: Option<Name>, pub name: Option<Name>,
pub type_ref: TypeRef, pub type_ref: TypeRef,
pub visibility: RawVisibility,
} }
impl ConstData { impl ConstData {
pub(crate) fn const_data_query(db: &impl DefDatabase, konst: ConstId) -> Arc<ConstData> { pub(crate) fn const_data_query(db: &impl DefDatabase, konst: ConstId) -> Arc<ConstData> {
let node = konst.lookup(db).source(db).value; let node = konst.lookup(db).source(db);
Arc::new(ConstData::new(&node)) Arc::new(ConstData::new(db, node))
} }
pub(crate) fn static_data_query(db: &impl DefDatabase, konst: StaticId) -> Arc<ConstData> { pub(crate) fn static_data_query(db: &impl DefDatabase, konst: StaticId) -> Arc<ConstData> {
let node = konst.lookup(db).source(db).value; let node = konst.lookup(db).source(db);
Arc::new(ConstData::new(&node)) Arc::new(ConstData::new(db, node))
} }
fn new<N: NameOwner + TypeAscriptionOwner + VisibilityOwner>(node: &N) -> ConstData { fn new<N: NameOwner + TypeAscriptionOwner + VisibilityOwner>(
let name = node.name().map(|n| n.as_name()); db: &impl DefDatabase,
let type_ref = TypeRef::from_ast_opt(node.ascribed_type()); node: InFile<N>,
ConstData { name, type_ref } ) -> ConstData {
let name = node.value.name().map(|n| n.as_name());
let type_ref = TypeRef::from_ast_opt(node.value.ascribed_type());
let visibility = RawVisibility::from_ast(db, node.map(|n| n.visibility()));
ConstData { name, type_ref, visibility }
} }
} }

View file

@ -1,6 +1,6 @@
//! Completion of paths, including when writing a single name. //! Completion of paths, including when writing a single name.
use hir::{Adt, PathResolution, ScopeDef, HasVisibility}; use hir::{Adt, HasVisibility, PathResolution, ScopeDef};
use ra_syntax::AstNode; use ra_syntax::AstNode;
use test_utils::tested_by; use test_utils::tested_by;
@ -52,9 +52,12 @@ pub(super) fn complete_path(acc: &mut Completions, ctx: &CompletionContext) {
if let Some(krate) = krate { if let Some(krate) = krate {
let traits_in_scope = ctx.scope().traits_in_scope(); let traits_in_scope = ctx.scope().traits_in_scope();
ty.iterate_path_candidates(ctx.db, krate, &traits_in_scope, None, |_ty, item| { ty.iterate_path_candidates(ctx.db, krate, &traits_in_scope, None, |_ty, item| {
if context_module.map_or(false, |m| !item.is_visible_from(ctx.db, m)) {
return None;
}
match item { match item {
hir::AssocItem::Function(func) => { hir::AssocItem::Function(func) => {
if !func.has_self_param(ctx.db) && context_module.map_or(true, |m| func.is_visible_from(ctx.db, m)) { if !func.has_self_param(ctx.db) {
acc.add_function(ctx, func); acc.add_function(ctx, func);
} }
} }
@ -65,6 +68,9 @@ pub(super) fn complete_path(acc: &mut Completions, ctx: &CompletionContext) {
}); });
ty.iterate_impl_items(ctx.db, krate, |item| { ty.iterate_impl_items(ctx.db, krate, |item| {
if context_module.map_or(false, |m| !item.is_visible_from(ctx.db, m)) {
return None;
}
match item { match item {
hir::AssocItem::Function(_) | hir::AssocItem::Const(_) => {} hir::AssocItem::Function(_) | hir::AssocItem::Const(_) => {}
hir::AssocItem::TypeAlias(ty) => acc.add_type_alias(ctx, ty), hir::AssocItem::TypeAlias(ty) => acc.add_type_alias(ctx, ty),
@ -75,6 +81,9 @@ pub(super) fn complete_path(acc: &mut Completions, ctx: &CompletionContext) {
} }
hir::ModuleDef::Trait(t) => { hir::ModuleDef::Trait(t) => {
for item in t.items(ctx.db) { for item in t.items(ctx.db) {
if context_module.map_or(false, |m| !item.is_visible_from(ctx.db, m)) {
continue;
}
match item { match item {
hir::AssocItem::Function(func) => { hir::AssocItem::Function(func) => {
if !func.has_self_param(ctx.db) { if !func.has_self_param(ctx.db) {
@ -537,6 +546,60 @@ mod tests {
); );
} }
#[test]
fn associated_item_visibility() {
assert_debug_snapshot!(
do_reference_completion(
"
//- /lib.rs
struct S;
mod m {
impl super::S {
pub(super) fn public_method() { }
fn private_method() { }
pub(super) type PublicType = u32;
type PrivateType = u32;
pub(super) const PUBLIC_CONST: u32 = 1;
const PRIVATE_CONST: u32 = 1;
}
}
fn foo() { let _ = S::<|> }
"
),
@r###"
[
CompletionItem {
label: "PUBLIC_CONST",
source_range: [302; 302),
delete: [302; 302),
insert: "PUBLIC_CONST",
kind: Const,
detail: "pub(super) const PUBLIC_CONST: u32 = 1;",
},
CompletionItem {
label: "PublicType",
source_range: [302; 302),
delete: [302; 302),
insert: "PublicType",
kind: TypeAlias,
detail: "pub(super) type PublicType = u32;",
},
CompletionItem {
label: "public_method()",
source_range: [302; 302),
delete: [302; 302),
insert: "public_method()$0",
kind: Function,
lookup: "public_method",
detail: "pub(super) fn public_method()",
},
]
"###
);
}
#[test] #[test]
fn completes_enum_associated_method() { fn completes_enum_associated_method() {
assert_debug_snapshot!( assert_debug_snapshot!(