Auto merge of #15473 - Veykril:doc-hidden-imports, r=Veykril

fix: Fix auto-import (and completions) importing `#[doc(hidden)]` items

Fixes https://github.com/rust-lang/rust-analyzer/issues/9197 and https://github.com/rust-lang/rust-analyzer/issues/9911

Turns out while https://github.com/rust-lang/rust-analyzer/pull/15472 didn't give access to the import stuff to the IDE layer, these can be fixed already since they use the import map which works in the hir-def crate 🎉
This commit is contained in:
bors 2023-08-17 10:49:42 +00:00
commit 44cf1745a8
7 changed files with 155 additions and 16 deletions

View File

@ -224,6 +224,7 @@ fn find_path_for_module(
) )
} }
// FIXME: Do we still need this now that we record import origins, and hence aliases?
fn find_in_scope( fn find_in_scope(
db: &dyn DefDatabase, db: &dyn DefDatabase,
def_map: &DefMap, def_map: &DefMap,
@ -346,6 +347,11 @@ fn calculate_best_path(
let extern_paths = crate_graph[from.krate].dependencies.iter().filter_map(|dep| { let extern_paths = crate_graph[from.krate].dependencies.iter().filter_map(|dep| {
let import_map = db.import_map(dep.crate_id); let import_map = db.import_map(dep.crate_id);
import_map.import_info_for(item).and_then(|info| { import_map.import_info_for(item).and_then(|info| {
if info.is_doc_hidden {
// the item or import is `#[doc(hidden)]`, so skip it as it is in an external crate
return None;
}
// Determine best path for containing module and append last segment from `info`. // Determine best path for containing module and append last segment from `info`.
// FIXME: we should guide this to look up the path locally, or from the same crate again? // FIXME: we should guide this to look up the path locally, or from the same crate again?
let mut path = find_path_for_module( let mut path = find_path_for_module(
@ -1311,4 +1317,47 @@ fn different_crate_renamed_through_dep() {
"intermediate::std_renamed::S", "intermediate::std_renamed::S",
); );
} }
#[test]
fn different_crate_doc_hidden() {
check_found_path(
r#"
//- /main.rs crate:main deps:intermediate
$0
//- /intermediate.rs crate:intermediate deps:std
#[doc(hidden)]
pub extern crate std;
pub extern crate std as longer;
//- /std.rs crate:std
pub struct S;
"#,
"intermediate::longer::S",
"intermediate::longer::S",
"intermediate::longer::S",
"intermediate::longer::S",
);
}
#[test]
fn respect_doc_hidden() {
check_found_path(
r#"
//- /main.rs crate:main deps:std,lazy_static
$0
//- /lazy_static.rs crate:lazy_static deps:core
#[doc(hidden)]
pub use core::ops::Deref as __Deref;
//- /std.rs crate:std deps:core
pub use core::ops;
//- /core.rs crate:core
pub mod ops {
pub trait Deref {}
}
"#,
"std::ops::Deref",
"std::ops::Deref",
"std::ops::Deref",
"std::ops::Deref",
);
}
} }

View File

@ -11,6 +11,7 @@
use rustc_hash::{FxHashMap, FxHashSet, FxHasher}; use rustc_hash::{FxHashMap, FxHashSet, FxHasher};
use triomphe::Arc; use triomphe::Arc;
use crate::item_scope::ImportOrExternCrate;
use crate::{ use crate::{
db::DefDatabase, item_scope::ItemInNs, nameres::DefMap, visibility::Visibility, AssocItemId, db::DefDatabase, item_scope::ItemInNs, nameres::DefMap, visibility::Visibility, AssocItemId,
ModuleDefId, ModuleId, TraitId, ModuleDefId, ModuleId, TraitId,
@ -29,6 +30,8 @@ pub struct ImportInfo {
pub container: ModuleId, pub container: ModuleId,
/// Whether the import is a trait associated item or not. /// Whether the import is a trait associated item or not.
pub is_trait_assoc_item: bool, pub is_trait_assoc_item: bool,
/// Whether this item is annotated with `#[doc(hidden)]`.
pub is_doc_hidden: bool,
} }
/// A map from publicly exported items to its name. /// A map from publicly exported items to its name.
@ -113,14 +116,27 @@ fn collect_import_map(db: &dyn DefDatabase, krate: CrateId) -> FxIndexMap<ItemIn
}); });
for (name, per_ns) in visible_items { for (name, per_ns) in visible_items {
for item in per_ns.iter_items() { for (item, import) in per_ns.iter_items() {
// FIXME: Not yet used, but will be once we handle doc(hidden) import sources // FIXME: Not yet used, but will be once we handle doc(hidden) import sources
let is_doc_hidden = false; let attr_id = if let Some(import) = import {
match import {
ImportOrExternCrate::ExternCrate(id) => Some(id.into()),
ImportOrExternCrate::Import(id) => Some(id.import.into()),
}
} else {
match item {
ItemInNs::Types(id) | ItemInNs::Values(id) => id.try_into().ok(),
ItemInNs::Macros(id) => Some(id.into()),
}
};
let is_doc_hidden =
attr_id.map_or(false, |attr_id| db.attrs(attr_id).has_doc_hidden());
let import_info = ImportInfo { let import_info = ImportInfo {
name: name.clone(), name: name.clone(),
container: module, container: module,
is_trait_assoc_item: false, is_trait_assoc_item: false,
is_doc_hidden,
}; };
match depth_map.entry(item) { match depth_map.entry(item) {
@ -171,10 +187,10 @@ fn collect_trait_assoc_items(
trait_import_info: &ImportInfo, trait_import_info: &ImportInfo,
) { ) {
let _p = profile::span("collect_trait_assoc_items"); let _p = profile::span("collect_trait_assoc_items");
for (assoc_item_name, item) in &db.trait_data(tr).items { for &(ref assoc_item_name, item) in &db.trait_data(tr).items {
let module_def_id = match item { let module_def_id = match item {
AssocItemId::FunctionId(f) => ModuleDefId::from(*f), AssocItemId::FunctionId(f) => ModuleDefId::from(f),
AssocItemId::ConstId(c) => ModuleDefId::from(*c), AssocItemId::ConstId(c) => ModuleDefId::from(c),
// cannot use associated type aliases directly: need a `<Struct as Trait>::TypeAlias` // cannot use associated type aliases directly: need a `<Struct as Trait>::TypeAlias`
// qualifier, ergo no need to store it for imports in import_map // qualifier, ergo no need to store it for imports in import_map
AssocItemId::TypeAliasId(_) => { AssocItemId::TypeAliasId(_) => {
@ -192,6 +208,7 @@ fn collect_trait_assoc_items(
container: trait_import_info.container, container: trait_import_info.container,
name: assoc_item_name.clone(), name: assoc_item_name.clone(),
is_trait_assoc_item: true, is_trait_assoc_item: true,
is_doc_hidden: db.attrs(item.into()).has_doc_hidden(),
}; };
map.insert(assoc_item, assoc_item_info); map.insert(assoc_item, assoc_item_info);
} }

View File

@ -66,7 +66,8 @@ pub struct ItemScope {
_c: Count<Self>, _c: Count<Self>,
/// Defs visible in this scope. This includes `declarations`, but also /// Defs visible in this scope. This includes `declarations`, but also
/// imports. /// imports. The imports belong to this module and can be resolved by using them on
/// the `use_imports_*` fields.
types: FxHashMap<Name, (ModuleDefId, Visibility, Option<ImportOrExternCrate>)>, types: FxHashMap<Name, (ModuleDefId, Visibility, Option<ImportOrExternCrate>)>,
values: FxHashMap<Name, (ModuleDefId, Visibility, Option<ImportId>)>, values: FxHashMap<Name, (ModuleDefId, Visibility, Option<ImportId>)>,
macros: FxHashMap<Name, (MacroId, Visibility, Option<ImportId>)>, macros: FxHashMap<Name, (MacroId, Visibility, Option<ImportId>)>,
@ -375,8 +376,8 @@ pub(crate) fn push_res_with_import(
None | Some(ImportType::Glob(_)) => None, None | Some(ImportType::Glob(_)) => None,
}; };
let prev = std::mem::replace(&mut fld.2, import); let prev = std::mem::replace(&mut fld.2, import);
if let Some(ImportOrExternCrate::Import(import)) = import { if let Some(import) = import {
self.use_imports_values.insert( self.use_imports_types.insert(
import, import,
match prev { match prev {
Some(ImportOrExternCrate::Import(import)) => { Some(ImportOrExternCrate::Import(import)) => {
@ -404,8 +405,8 @@ pub(crate) fn push_res_with_import(
None | Some(ImportType::Glob(_)) => None, None | Some(ImportType::Glob(_)) => None,
}; };
let prev = std::mem::replace(&mut fld.2, import); let prev = std::mem::replace(&mut fld.2, import);
if let Some(ImportOrExternCrate::Import(import)) = import { if let Some(import) = import {
self.use_imports_values.insert( self.use_imports_types.insert(
import, import,
match prev { match prev {
Some(ImportOrExternCrate::Import(import)) => { Some(ImportOrExternCrate::Import(import)) => {

View File

@ -870,7 +870,8 @@ pub enum AttrDefId {
MacroId(Macro2Id, MacroRulesId, ProcMacroId), MacroId(Macro2Id, MacroRulesId, ProcMacroId),
ImplId, ImplId,
GenericParamId, GenericParamId,
ExternCrateId ExternCrateId,
UseId
for AttrDefId for AttrDefId
); );
@ -904,6 +905,15 @@ fn from(acid: ItemContainerId) -> Self {
} }
} }
} }
impl From<AssocItemId> for AttrDefId {
fn from(assoc: AssocItemId) -> Self {
match assoc {
AssocItemId::FunctionId(it) => AttrDefId::FunctionId(it),
AssocItemId::ConstId(it) => AttrDefId::ConstId(it),
AssocItemId::TypeAliasId(it) => AttrDefId::TypeAliasId(it),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum VariantId { pub enum VariantId {

View File

@ -117,12 +117,20 @@ pub fn or_else(self, f: impl FnOnce() -> PerNs) -> PerNs {
} }
} }
pub fn iter_items(self) -> impl Iterator<Item = ItemInNs> { pub fn iter_items(self) -> impl Iterator<Item = (ItemInNs, Option<ImportOrExternCrate>)> {
let _p = profile::span("PerNs::iter_items"); let _p = profile::span("PerNs::iter_items");
self.types self.types
.map(|it| ItemInNs::Types(it.0)) .map(|it| (ItemInNs::Types(it.0), it.2))
.into_iter() .into_iter()
.chain(self.values.map(|it| ItemInNs::Values(it.0)).into_iter()) .chain(
.chain(self.macros.map(|it| ItemInNs::Macros(it.0)).into_iter()) self.values
.map(|it| (ItemInNs::Values(it.0), it.2.map(ImportOrExternCrate::Import)))
.into_iter(),
)
.chain(
self.macros
.map(|it| (ItemInNs::Macros(it.0), it.2.map(ImportOrExternCrate::Import)))
.into_iter(),
)
} }
} }

View File

@ -212,7 +212,7 @@ fn resolve_doc_path(
Some(Namespace::Types) => resolved.take_types(), Some(Namespace::Types) => resolved.take_types(),
Some(Namespace::Values) => resolved.take_values(), Some(Namespace::Values) => resolved.take_values(),
Some(Namespace::Macros) => resolved.take_macros().map(ModuleDefId::MacroId), Some(Namespace::Macros) => resolved.take_macros().map(ModuleDefId::MacroId),
None => resolved.iter_items().next().map(|it| match it { None => resolved.iter_items().next().map(|(it, _)| match it {
ItemInNs::Types(it) => it, ItemInNs::Types(it) => it,
ItemInNs::Values(it) => it, ItemInNs::Values(it) => it,
ItemInNs::Macros(it) => ModuleDefId::MacroId(it), ItemInNs::Macros(it) => ModuleDefId::MacroId(it),

View File

@ -1286,3 +1286,57 @@ macro_rules! println {
expect![""], expect![""],
) )
} }
#[test]
fn no_completions_for_external_doc_hidden_in_path() {
check(
r#"
//- /main.rs crate:main deps:dep
fn main() {
Span$0
}
//- /lib.rs crate:dep
#[doc(hidden)]
pub mod bridge {
pub mod server {
pub trait Span
}
}
pub mod bridge2 {
#[doc(hidden)]
pub mod server2 {
pub trait Span
}
}
"#,
expect![""],
);
// unless re-exported
check(
r#"
//- /main.rs crate:main deps:dep
fn main() {
Span$0
}
//- /lib.rs crate:dep
#[doc(hidden)]
pub mod bridge {
pub mod server {
pub trait Span
}
}
pub use bridge::server::Span;
pub mod bridge2 {
#[doc(hidden)]
pub mod server2 {
pub trait Span2
}
}
pub use bridge2::server2::Span2;
"#,
expect![[r#"
tt Span (use dep::Span)
tt Span2 (use dep::Span2)
"#]],
);
}