mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-27 05:23:24 +00:00
Handle visibility for assoc item path completion as well
This commit is contained in:
parent
d9c77c5453
commit
05e1c7b197
3 changed files with 124 additions and 22 deletions
|
@ -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),
|
||||||
|
|
|
@ -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 }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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!(
|
||||||
|
|
Loading…
Reference in a new issue