mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-10-03 07:04:49 +00:00
parent
b3ef934ccb
commit
25242fe93f
395 changed files with 14569 additions and 5755 deletions
|
@ -2,7 +2,9 @@
|
|||
use std::fmt::Display;
|
||||
|
||||
use either::Either;
|
||||
use hir::{AsAssocItem, AttributeTemplate, HasAttrs, HasSource, HirDisplay, Semantics, TypeInfo};
|
||||
use hir::{
|
||||
Adt, AsAssocItem, AttributeTemplate, HasAttrs, HasSource, HirDisplay, Semantics, TypeInfo,
|
||||
};
|
||||
use ide_db::{
|
||||
base_db::SourceDatabase,
|
||||
defs::Definition,
|
||||
|
@ -14,7 +16,9 @@ use ide_db::{
|
|||
use itertools::Itertools;
|
||||
use stdx::format_to;
|
||||
use syntax::{
|
||||
algo, ast, match_ast, AstNode, Direction,
|
||||
algo,
|
||||
ast::{self, RecordPat},
|
||||
match_ast, AstNode, Direction,
|
||||
SyntaxKind::{LET_EXPR, LET_STMT},
|
||||
SyntaxToken, T,
|
||||
};
|
||||
|
@ -250,6 +254,50 @@ pub(super) fn keyword(
|
|||
Some(HoverResult { markup, actions })
|
||||
}
|
||||
|
||||
/// Returns missing types in a record pattern.
|
||||
/// Only makes sense when there's a rest pattern in the record pattern.
|
||||
/// i.e. `let S {a, ..} = S {a: 1, b: 2}`
|
||||
pub(super) fn struct_rest_pat(
|
||||
sema: &Semantics<'_, RootDatabase>,
|
||||
config: &HoverConfig,
|
||||
pattern: &RecordPat,
|
||||
) -> HoverResult {
|
||||
let missing_fields = sema.record_pattern_missing_fields(pattern);
|
||||
|
||||
// if there are no missing fields, the end result is a hover that shows ".."
|
||||
// should be left in to indicate that there are no more fields in the pattern
|
||||
// example, S {a: 1, b: 2, ..} when struct S {a: u32, b: u32}
|
||||
|
||||
let mut res = HoverResult::default();
|
||||
let mut targets: Vec<hir::ModuleDef> = Vec::new();
|
||||
let mut push_new_def = |item: hir::ModuleDef| {
|
||||
if !targets.contains(&item) {
|
||||
targets.push(item);
|
||||
}
|
||||
};
|
||||
for (_, t) in &missing_fields {
|
||||
walk_and_push_ty(sema.db, t, &mut push_new_def);
|
||||
}
|
||||
|
||||
res.markup = {
|
||||
let mut s = String::from(".., ");
|
||||
for (f, _) in &missing_fields {
|
||||
s += f.display(sema.db).to_string().as_ref();
|
||||
s += ", ";
|
||||
}
|
||||
// get rid of trailing comma
|
||||
s.truncate(s.len() - 2);
|
||||
|
||||
if config.markdown() {
|
||||
Markup::fenced_block(&s)
|
||||
} else {
|
||||
s.into()
|
||||
}
|
||||
};
|
||||
res.actions.push(HoverAction::goto_type_from_targets(sema.db, targets));
|
||||
res
|
||||
}
|
||||
|
||||
pub(super) fn try_for_lint(attr: &ast::Attr, token: &SyntaxToken) -> Option<HoverResult> {
|
||||
let (path, tt) = attr.as_simple_call()?;
|
||||
if !tt.syntax().text_range().contains(token.text_range().start()) {
|
||||
|
@ -342,15 +390,35 @@ pub(super) fn definition(
|
|||
let mod_path = definition_mod_path(db, &def);
|
||||
let (label, docs) = match def {
|
||||
Definition::Macro(it) => label_and_docs(db, it),
|
||||
Definition::Field(it) => label_and_docs(db, it),
|
||||
Definition::Field(it) => label_and_layout_info_and_docs(db, it, |&it| {
|
||||
let var_def = it.parent_def(db);
|
||||
let id = it.index();
|
||||
let layout = it.layout(db).ok()?;
|
||||
let offset = match var_def {
|
||||
hir::VariantDef::Struct(s) => Adt::from(s)
|
||||
.layout(db)
|
||||
.ok()
|
||||
.map(|layout| format!(", offset = {}", layout.fields.offset(id).bytes())),
|
||||
_ => None,
|
||||
};
|
||||
Some(format!(
|
||||
"size = {}, align = {}{}",
|
||||
layout.size.bytes(),
|
||||
layout.align.abi.bytes(),
|
||||
offset.as_deref().unwrap_or_default()
|
||||
))
|
||||
}),
|
||||
Definition::Module(it) => label_and_docs(db, it),
|
||||
Definition::Function(it) => label_and_docs(db, it),
|
||||
Definition::Adt(it) => label_and_docs(db, it),
|
||||
Definition::Adt(it) => label_and_layout_info_and_docs(db, it, |&it| {
|
||||
let layout = it.layout(db).ok()?;
|
||||
Some(format!("size = {}, align = {}", layout.size.bytes(), layout.align.abi.bytes()))
|
||||
}),
|
||||
Definition::Variant(it) => label_value_and_docs(db, it, |&it| {
|
||||
if !it.parent_enum(db).is_data_carrying(db) {
|
||||
match it.eval(db) {
|
||||
Ok(x) => Some(format!("{}", x)),
|
||||
Err(_) => it.value(db).map(|x| format!("{:?}", x)),
|
||||
Ok(x) => Some(format!("{x}")),
|
||||
Err(_) => it.value(db).map(|x| format!("{x:?}")),
|
||||
}
|
||||
} else {
|
||||
None
|
||||
|
@ -359,7 +427,7 @@ pub(super) fn definition(
|
|||
Definition::Const(it) => label_value_and_docs(db, it, |it| {
|
||||
let body = it.eval(db);
|
||||
match body {
|
||||
Ok(x) => Some(format!("{}", x)),
|
||||
Ok(x) => Some(format!("{x}")),
|
||||
Err(_) => {
|
||||
let source = it.source(db)?;
|
||||
let mut body = source.value.body()?.syntax().clone();
|
||||
|
@ -415,7 +483,7 @@ pub(super) fn definition(
|
|||
|
||||
fn render_builtin_attr(db: &RootDatabase, attr: hir::BuiltinAttr) -> Option<Markup> {
|
||||
let name = attr.name(db);
|
||||
let desc = format!("#[{}]", name);
|
||||
let desc = format!("#[{name}]");
|
||||
|
||||
let AttributeTemplate { word, list, name_value_str } = match attr.template(db) {
|
||||
Some(template) => template,
|
||||
|
@ -443,6 +511,25 @@ where
|
|||
(label, docs)
|
||||
}
|
||||
|
||||
fn label_and_layout_info_and_docs<D, E, V>(
|
||||
db: &RootDatabase,
|
||||
def: D,
|
||||
value_extractor: E,
|
||||
) -> (String, Option<hir::Documentation>)
|
||||
where
|
||||
D: HasAttrs + HirDisplay,
|
||||
E: Fn(&D) -> Option<V>,
|
||||
V: Display,
|
||||
{
|
||||
let label = if let Some(value) = value_extractor(&def) {
|
||||
format!("{} // {value}", def.display(db))
|
||||
} else {
|
||||
def.display(db).to_string()
|
||||
};
|
||||
let docs = def.attrs(db).docs();
|
||||
(label, docs)
|
||||
}
|
||||
|
||||
fn label_value_and_docs<D, E, V>(
|
||||
db: &RootDatabase,
|
||||
def: D,
|
||||
|
@ -454,7 +541,7 @@ where
|
|||
V: Display,
|
||||
{
|
||||
let label = if let Some(value) = value_extractor(&def) {
|
||||
format!("{} = {}", def.display(db), value)
|
||||
format!("{} = {value}", def.display(db))
|
||||
} else {
|
||||
def.display(db).to_string()
|
||||
};
|
||||
|
@ -518,9 +605,9 @@ fn local(db: &RootDatabase, it: hir::Local) -> Option<Markup> {
|
|||
} else {
|
||||
""
|
||||
};
|
||||
format!("{}{}{}: {}", let_kw, is_mut, name, ty)
|
||||
format!("{let_kw}{is_mut}{name}: {ty}")
|
||||
}
|
||||
Either::Right(_) => format!("{}self: {}", is_mut, ty),
|
||||
Either::Right(_) => format!("{is_mut}self: {ty}"),
|
||||
};
|
||||
markup(None, desc, None)
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue