Unnamed repository; edit this file 'description' to name the repository.
Adjust block-local impl item visibility rendering
Ryo Yoshida 2023-02-19
parent 83e24fe · commit d416623
-rw-r--r--crates/hir/src/display.rs31
-rw-r--r--crates/hir/src/lib.rs16
-rw-r--r--crates/ide/src/hover/tests.rs178
3 files changed, 216 insertions, 9 deletions
diff --git a/crates/hir/src/display.rs b/crates/hir/src/display.rs
index 830d261d78..66bf2a2900 100644
--- a/crates/hir/src/display.rs
+++ b/crates/hir/src/display.rs
@@ -17,15 +17,23 @@ use hir_ty::{
};
use crate::{
- Adt, Const, ConstParam, Enum, Field, Function, GenericParam, HasCrate, HasVisibility,
- LifetimeParam, Macro, Module, Static, Struct, Trait, TyBuilder, Type, TypeAlias,
- TypeOrConstParam, TypeParam, Union, Variant,
+ Adt, AsAssocItem, AssocItemContainer, Const, ConstParam, Enum, Field, Function, GenericParam,
+ HasCrate, HasVisibility, LifetimeParam, Macro, Module, Static, Struct, Trait, TyBuilder, Type,
+ TypeAlias, TypeOrConstParam, TypeParam, Union, Variant,
};
impl HirDisplay for Function {
fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
- let data = f.db.function_data(self.id);
- write_visibility(self.module(f.db).id, self.visibility(f.db), f)?;
+ let db = f.db;
+ let data = db.function_data(self.id);
+ let container = self.as_assoc_item(db).map(|it| it.container(db));
+ let mut module = self.module(db);
+ if let Some(AssocItemContainer::Impl(_)) = container {
+ // Block-local impls are "hoisted" to the nearest (non-block) module.
+ module = module.nearest_non_block_module(db);
+ }
+ let module_id = module.id;
+ write_visibility(module_id, self.visibility(db), f)?;
if data.has_default_kw() {
f.write_str("default ")?;
}
@@ -35,7 +43,7 @@ impl HirDisplay for Function {
if data.has_async_kw() {
f.write_str("async ")?;
}
- if self.is_unsafe_to_call(f.db) {
+ if self.is_unsafe_to_call(db) {
f.write_str("unsafe ")?;
}
if let Some(abi) = &data.abi {
@@ -442,8 +450,15 @@ fn write_where_clause(def: GenericDefId, f: &mut HirFormatter<'_>) -> Result<(),
impl HirDisplay for Const {
fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
- write_visibility(self.module(f.db).id, self.visibility(f.db), f)?;
- let data = f.db.const_data(self.id);
+ let db = f.db;
+ let container = self.as_assoc_item(db).map(|it| it.container(db));
+ let mut module = self.module(db);
+ if let Some(AssocItemContainer::Impl(_)) = container {
+ // Block-local impls are "hoisted" to the nearest (non-block) module.
+ module = module.nearest_non_block_module(db);
+ }
+ write_visibility(module.id, self.visibility(db), f)?;
+ let data = db.const_data(self.id);
f.write_str("const ")?;
match &data.name {
Some(name) => write!(f, "{name}: ")?,
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index 2cb4ed2c33..4db0e20098 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -46,7 +46,7 @@ use hir_def::{
item_tree::ItemTreeNode,
lang_item::{LangItem, LangItemTarget},
layout::{Layout, LayoutError, ReprOptions},
- nameres::{self, diagnostics::DefDiagnostic},
+ nameres::{self, diagnostics::DefDiagnostic, ModuleOrigin},
per_ns::PerNs,
resolver::{HasResolver, Resolver},
src::HasSource as _,
@@ -488,6 +488,20 @@ impl Module {
Some(Module { id: def_map.module_id(parent_id) })
}
+ /// Finds nearest non-block ancestor `Module` (`self` included).
+ fn nearest_non_block_module(self, db: &dyn HirDatabase) -> Module {
+ let mut id = self.id;
+ loop {
+ let def_map = id.def_map(db.upcast());
+ let origin = def_map[id.local_id].origin;
+ if matches!(origin, ModuleOrigin::BlockExpr { .. }) {
+ id = id.containing_module(db.upcast()).expect("block without parent module")
+ } else {
+ return Module { id };
+ }
+ }
+ }
+
pub fn path_to_root(self, db: &dyn HirDatabase) -> Vec<Module> {
let mut res = vec![self];
let mut curr = self;
diff --git a/crates/ide/src/hover/tests.rs b/crates/ide/src/hover/tests.rs
index bd7ce2f1d0..c199d1040a 100644
--- a/crates/ide/src/hover/tests.rs
+++ b/crates/ide/src/hover/tests.rs
@@ -5647,3 +5647,181 @@ fn main() {
"#]],
);
}
+
+#[test]
+fn assoc_fn_in_block_local_impl() {
+ check(
+ r#"
+struct S;
+mod m {
+ const _: () = {
+ impl crate::S {
+ pub(crate) fn foo() {}
+ }
+ };
+}
+fn test() {
+ S::foo$0();
+}
+"#,
+ expect![[r#"
+ *foo*
+
+ ```rust
+ test::S
+ ```
+
+ ```rust
+ pub(crate) fn foo()
+ ```
+ "#]],
+ );
+
+ check(
+ r#"
+struct S;
+mod m {
+ const _: () = {
+ const _: () = {
+ impl crate::S {
+ pub(crate) fn foo() {}
+ }
+ };
+ };
+}
+fn test() {
+ S::foo$0();
+}
+"#,
+ expect![[r#"
+ *foo*
+
+ ```rust
+ test::S
+ ```
+
+ ```rust
+ pub(crate) fn foo()
+ ```
+ "#]],
+ );
+
+ check(
+ r#"
+struct S;
+mod m {
+ mod inner {
+ const _: () = {
+ impl crate::S {
+ pub(super) fn foo() {}
+ }
+ };
+ }
+
+ fn test() {
+ crate::S::foo$0();
+ }
+}
+"#,
+ expect![[r#"
+ *foo*
+
+ ```rust
+ test::S
+ ```
+
+ ```rust
+ pub(super) fn foo()
+ ```
+ "#]],
+ );
+}
+
+#[test]
+fn assoc_const_in_block_local_impl() {
+ check(
+ r#"
+struct S;
+mod m {
+ const _: () = {
+ impl crate::S {
+ pub(crate) const A: () = ();
+ }
+ };
+}
+fn test() {
+ S::A$0;
+}
+"#,
+ expect![[r#"
+ *A*
+
+ ```rust
+ test
+ ```
+
+ ```rust
+ pub(crate) const A: () = ()
+ ```
+ "#]],
+ );
+
+ check(
+ r#"
+struct S;
+mod m {
+ const _: () = {
+ const _: () = {
+ impl crate::S {
+ pub(crate) const A: () = ();
+ }
+ };
+ };
+}
+fn test() {
+ S::A$0;
+}
+"#,
+ expect![[r#"
+ *A*
+
+ ```rust
+ test
+ ```
+
+ ```rust
+ pub(crate) const A: () = ()
+ ```
+ "#]],
+ );
+
+ check(
+ r#"
+struct S;
+mod m {
+ mod inner {
+ const _: () = {
+ impl crate::S {
+ pub(super) const A: () = ();
+ }
+ };
+ }
+
+ fn test() {
+ crate::S::A$0;
+ }
+}
+"#,
+ expect![[r#"
+ *A*
+
+ ```rust
+ test
+ ```
+
+ ```rust
+ pub(super) const A: () = ()
+ ```
+ "#]],
+ );
+}