Skip to content

Do not render meta info when hovering usages #18436

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Oct 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 16 additions & 1 deletion crates/hir/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,10 @@ pub mod term_search;

mod display;

use std::{mem::discriminant, ops::ControlFlow};
use std::{
mem::discriminant,
ops::{ControlFlow, Not},
};

use arrayvec::ArrayVec;
use base_db::{CrateDisplayName, CrateId, CrateOrigin};
Expand Down Expand Up @@ -2697,6 +2700,18 @@ impl Trait {
hir_ty::dyn_compatibility::dyn_compatibility(db, self.id)
}

pub fn dyn_compatibility_all_violations(
&self,
db: &dyn HirDatabase,
) -> Option<Vec<DynCompatibilityViolation>> {
let mut violations = vec![];
hir_ty::dyn_compatibility::dyn_compatibility_with_callback(db, self.id, &mut |violation| {
violations.push(violation);
ControlFlow::Continue(())
});
violations.is_empty().not().then_some(violations)
}

fn all_macro_calls(&self, db: &dyn HirDatabase) -> Box<[(AstId<ast::Item>, MacroCallId)]> {
db.trait_data(self.id)
.macro_calls
Expand Down
33 changes: 26 additions & 7 deletions crates/ide/src/hover.rs
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ fn hover_offset(
if let Some(doc_comment) = token_as_doc_comment(&original_token) {
cov_mark::hit!(no_highlight_on_comment_hover);
return doc_comment.get_definition_with_descend_at(sema, offset, |def, node, range| {
let res = hover_for_definition(sema, file_id, def, &node, None, config, edition);
let res = hover_for_definition(sema, file_id, def, &node, None, false, config, edition);
Some(RangeInfo::new(range, res))
});
}
Expand All @@ -172,6 +172,7 @@ fn hover_offset(
Definition::from(resolution?),
&original_token.parent()?,
None,
false,
config,
edition,
);
Expand Down Expand Up @@ -218,6 +219,7 @@ fn hover_offset(
break 'a vec![(
Definition::Macro(macro_),
sema.resolve_macro_call_arm(&macro_call),
false,
node,
)];
}
Expand All @@ -234,19 +236,34 @@ fn hover_offset(
decl,
..
}) => {
vec![(Definition::ExternCrateDecl(decl), None, node)]
vec![(Definition::ExternCrateDecl(decl), None, false, node)]
}

class => {
multizip((class.definitions(), iter::repeat(None), iter::repeat(node)))
.collect::<Vec<_>>()
let is_def = matches!(class, IdentClass::NameClass(_));
multizip((
class.definitions(),
iter::repeat(None),
iter::repeat(is_def),
iter::repeat(node),
))
.collect::<Vec<_>>()
}
}
}
.into_iter()
.unique_by(|&(def, _, _)| def)
.map(|(def, macro_arm, node)| {
hover_for_definition(sema, file_id, def, &node, macro_arm, config, edition)
.unique_by(|&(def, _, _, _)| def)
.map(|(def, macro_arm, hovered_definition, node)| {
hover_for_definition(
sema,
file_id,
def,
&node,
macro_arm,
hovered_definition,
config,
edition,
)
})
.collect::<Vec<_>>(),
)
Expand Down Expand Up @@ -366,6 +383,7 @@ pub(crate) fn hover_for_definition(
def: Definition,
scope_node: &SyntaxNode,
macro_arm: Option<u32>,
hovered_definition: bool,
config: &HoverConfig,
edition: Edition,
) -> HoverResult {
Expand Down Expand Up @@ -397,6 +415,7 @@ pub(crate) fn hover_for_definition(
famous_defs.as_ref(),
&notable_traits,
macro_arm,
hovered_definition,
config,
edition,
);
Expand Down
137 changes: 72 additions & 65 deletions crates/ide/src/hover/render.rs
Original file line number Diff line number Diff line change
Expand Up @@ -273,7 +273,7 @@ pub(super) fn keyword(
let markup = process_markup(
sema.db,
Definition::Module(doc_owner),
&markup(Some(docs.into()), description, None),
&markup(Some(docs.into()), description, None, None),
config,
);
Some(HoverResult { markup, actions })
Expand Down Expand Up @@ -419,6 +419,7 @@ pub(super) fn definition(
famous_defs: Option<&FamousDefs<'_, '_>>,
notable_traits: &[(Trait, Vec<(Option<Type>, Name)>)],
macro_arm: Option<u32>,
hovered_definition: bool,
config: &HoverConfig,
edition: Edition,
) -> Markup {
Expand Down Expand Up @@ -456,7 +457,7 @@ pub(super) fn definition(
_ => def.label(db, edition),
};
let docs = def.docs(db, famous_defs, edition);
let value = (|| match def {
let value = || match def {
Definition::Variant(it) => {
if !it.parent_enum(db).is_data_carrying(db) {
match it.eval(db) {
Expand Down Expand Up @@ -494,9 +495,9 @@ pub(super) fn definition(
Some(body.to_string())
}
_ => None,
})();
};

let layout_info = match def {
let layout_info = || match def {
Definition::Field(it) => render_memory_layout(
config.memory_layout,
|| it.layout(db),
Expand Down Expand Up @@ -529,34 +530,38 @@ pub(super) fn definition(
_ => None,
};

let dyn_compatibility_info = if let Definition::Trait(it) = def {
let mut dyn_compatibility_info = String::new();
render_dyn_compatibility(db, &mut dyn_compatibility_info, it.dyn_compatibility(db));
Some(dyn_compatibility_info)
} else {
None
let dyn_compatibility_info = || match def {
Definition::Trait(it) => {
let mut dyn_compatibility_info = String::new();
render_dyn_compatibility(db, &mut dyn_compatibility_info, it.dyn_compatibility(db));
Some(dyn_compatibility_info)
}
_ => None,
};

let mut desc = String::new();
if let Some(notable_traits) = render_notable_trait_comment(db, notable_traits, edition) {
desc.push_str(&notable_traits);
desc.push('\n');
}
if let Some(layout_info) = layout_info {
desc.push_str(&layout_info);
desc.push('\n');
}
if let Some(dyn_compatibility_info) = dyn_compatibility_info {
desc.push_str(&dyn_compatibility_info);
desc.push('\n');
let mut extra = String::new();
if hovered_definition {
if let Some(notable_traits) = render_notable_trait(db, notable_traits, edition) {
extra.push_str("\n___\n");
extra.push_str(&notable_traits);
}
if let Some(layout_info) = layout_info() {
extra.push_str("\n___\n");
extra.push_str(&layout_info);
}
if let Some(dyn_compatibility_info) = dyn_compatibility_info() {
extra.push_str("\n___\n");
extra.push_str(&dyn_compatibility_info);
}
}
let mut desc = String::new();
desc.push_str(&label);
if let Some(value) = value {
if let Some(value) = value() {
desc.push_str(" = ");
desc.push_str(&value);
}

markup(docs.map(Into::into), desc, mod_path)
markup(docs.map(Into::into), desc, extra.is_empty().not().then_some(extra), mod_path)
}

pub(super) fn literal(
Expand Down Expand Up @@ -626,7 +631,7 @@ pub(super) fn literal(
Some(s.into())
}

fn render_notable_trait_comment(
fn render_notable_trait(
db: &RootDatabase,
notable_traits: &[(Trait, Vec<(Option<Type>, Name)>)],
edition: Edition,
Expand All @@ -635,7 +640,7 @@ fn render_notable_trait_comment(
let mut needs_impl_header = true;
for (trait_, assoc_types) in notable_traits {
desc.push_str(if mem::take(&mut needs_impl_header) {
"// Implements notable traits: "
"Implements notable traits: "
} else {
", "
});
Expand Down Expand Up @@ -728,13 +733,12 @@ fn type_info(
)
.into()
} else {
let mut desc =
match render_notable_trait_comment(db, &notable_traits(db, &original), edition) {
Some(desc) => desc + "\n",
None => String::new(),
};
format_to!(desc, "{}", original.display(db, edition));
Markup::fenced_block(&desc)
let mut desc = format!("```rust\n{}\n```", original.display(db, edition));
if let Some(extra) = render_notable_trait(db, &notable_traits(db, &original), edition) {
desc.push_str("\n___\n");
desc.push_str(&extra);
};
desc.into()
};
if let Some(actions) = HoverAction::goto_type_from_targets(db, targets, edition) {
res.actions.push(actions);
Expand Down Expand Up @@ -786,20 +790,16 @@ fn closure_ty(
};
let mut markup = format!("```rust\n{}", c.display_with_id(sema.db, edition));

if let Some(trait_) = c.fn_trait(sema.db).get_id(sema.db, original.krate(sema.db).into()) {
push_new_def(hir::Trait::from(trait_).into())
}
format_to!(markup, "\n{}\n```", c.display_with_impl(sema.db, edition),);
if let Some(layout) =
render_memory_layout(config.memory_layout, || original.layout(sema.db), |_| None, |_| None)
{
format_to!(markup, " {layout}");
format_to!(markup, "\n___\n{layout}");
}
if let Some(trait_) = c.fn_trait(sema.db).get_id(sema.db, original.krate(sema.db).into()) {
push_new_def(hir::Trait::from(trait_).into())
}
format_to!(
markup,
"\n{}\n```{adjusted}\n\n## Captures\n{}",
c.display_with_impl(sema.db, edition),
captures_rendered,
);
format_to!(markup, "{adjusted}\n\n## Captures\n{}", captures_rendered,);

let mut res = HoverResult::default();
if let Some(actions) = HoverAction::goto_type_from_targets(sema.db, targets, edition) {
Expand All @@ -824,15 +824,24 @@ fn definition_mod_path(db: &RootDatabase, def: &Definition, edition: Edition) ->
.map(|module| path(db, module, definition_owner_name(db, def, edition), edition))
}

fn markup(docs: Option<String>, desc: String, mod_path: Option<String>) -> Markup {
fn markup(
docs: Option<String>,
rust: String,
extra: Option<String>,
mod_path: Option<String>,
) -> Markup {
let mut buf = String::new();

if let Some(mod_path) = mod_path {
if !mod_path.is_empty() {
format_to!(buf, "```rust\n{}\n```\n\n", mod_path);
}
}
format_to!(buf, "```rust\n{}\n```", desc);
format_to!(buf, "```rust\n{}\n```", rust);

if let Some(extra) = extra {
buf.push_str(&extra);
}

if let Some(doc) = docs {
format_to!(buf, "\n___\n\n{}", doc);
Expand Down Expand Up @@ -862,7 +871,7 @@ fn render_memory_layout(
let config = config?;
let layout = layout().ok()?;

let mut label = String::from("// ");
let mut label = String::new();

if let Some(render) = config.size {
let size = match tag(&layout) {
Expand Down Expand Up @@ -994,55 +1003,53 @@ fn render_dyn_compatibility(
safety: Option<DynCompatibilityViolation>,
) {
let Some(osv) = safety else {
buf.push_str("// Dyn Compatible: Yes");
buf.push_str("Is Dyn compatible");
return;
};
buf.push_str("// Dyn Compatible: No\n// - Reason: ");
buf.push_str("Is not Dyn compatible due to ");
match osv {
DynCompatibilityViolation::SizedSelf => {
buf.push_str("has a `Self: Sized` bound");
buf.push_str("having a `Self: Sized` bound");
}
DynCompatibilityViolation::SelfReferential => {
buf.push_str("has a bound that references `Self`");
buf.push_str("having a bound that references `Self`");
}
DynCompatibilityViolation::Method(func, mvc) => {
let name = hir::Function::from(func).name(db);
format_to!(
buf,
"has a method `{}` that is non dispatchable because of:\n// - ",
name.as_str()
);
format_to!(buf, "having a method `{}` that is not dispatchable due to ", name.as_str());
let desc = match mvc {
MethodViolationCode::StaticMethod => "missing a receiver",
MethodViolationCode::ReferencesSelfInput => "a parameter references `Self`",
MethodViolationCode::ReferencesSelfOutput => "the return type references `Self`",
MethodViolationCode::ReferencesSelfInput => "having a parameter referencing `Self`",
MethodViolationCode::ReferencesSelfOutput => "the return type referencing `Self`",
MethodViolationCode::ReferencesImplTraitInTrait => {
"the return type contains `impl Trait`"
"the return type containing `impl Trait`"
}
MethodViolationCode::AsyncFn => "being async",
MethodViolationCode::WhereClauseReferencesSelf => {
"a where clause references `Self`"
"a where clause referencing `Self`"
}
MethodViolationCode::Generic => "having a const or type generic parameter",
MethodViolationCode::UndispatchableReceiver => {
"having a non-dispatchable receiver type"
}
MethodViolationCode::Generic => "a non-lifetime generic parameter",
MethodViolationCode::UndispatchableReceiver => "a non-dispatchable receiver type",
};
buf.push_str(desc);
}
DynCompatibilityViolation::AssocConst(const_) => {
let name = hir::Const::from(const_).name(db);
if let Some(name) = name {
format_to!(buf, "has an associated constant `{}`", name.as_str());
format_to!(buf, "having an associated constant `{}`", name.as_str());
} else {
buf.push_str("has an associated constant");
buf.push_str("having an associated constant");
}
}
DynCompatibilityViolation::GAT(alias) => {
let name = hir::TypeAlias::from(alias).name(db);
format_to!(buf, "has a generic associated type `{}`", name.as_str());
format_to!(buf, "having a generic associated type `{}`", name.as_str());
}
DynCompatibilityViolation::HasNonCompatibleSuperTrait(super_trait) => {
let name = hir::Trait::from(super_trait).name(db);
format_to!(buf, "has a dyn incompatible supertrait `{}`", name.as_str());
format_to!(buf, "having a dyn incompatible supertrait `{}`", name.as_str());
}
}
}
Loading