⬆️ rust-analyzer

Merge commit '368e0bb32f'
This commit is contained in:
arcnmx 2023-01-09 10:36:22 -08:00
parent b3ef934ccb
commit 25242fe93f
395 changed files with 14569 additions and 5755 deletions

View file

@ -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)
}