mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-26 13:03:31 +00:00
Fix goto definition for record patterns
This commit is contained in:
parent
ca61356b01
commit
fa2ea8f494
7 changed files with 57 additions and 6 deletions
|
@ -195,6 +195,10 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
|
|||
self.analyze(field.syntax()).resolve_record_field(self.db, field)
|
||||
}
|
||||
|
||||
pub fn resolve_record_field_pat(&self, field: &ast::RecordFieldPat) -> Option<StructField> {
|
||||
self.analyze(field.syntax()).resolve_record_field_pat(self.db, field)
|
||||
}
|
||||
|
||||
pub fn resolve_macro_call(&self, macro_call: &ast::MacroCall) -> Option<MacroDef> {
|
||||
let sa = self.analyze(macro_call.syntax());
|
||||
let macro_call = self.find_file(macro_call.syntax().clone()).with_value(macro_call);
|
||||
|
|
|
@ -95,6 +95,7 @@ impl SourceAnalyzer {
|
|||
}
|
||||
|
||||
fn pat_id(&self, pat: &ast::Pat) -> Option<PatId> {
|
||||
// FIXME: macros, see `expr_id`
|
||||
let src = InFile { file_id: self.file_id, value: pat };
|
||||
self.body_source_map.as_ref()?.node_pat(src)
|
||||
}
|
||||
|
@ -167,6 +168,16 @@ impl SourceAnalyzer {
|
|||
Some((struct_field.into(), local))
|
||||
}
|
||||
|
||||
pub(crate) fn resolve_record_field_pat(
|
||||
&self,
|
||||
_db: &dyn HirDatabase,
|
||||
field: &ast::RecordFieldPat,
|
||||
) -> Option<StructField> {
|
||||
let pat_id = self.pat_id(&field.pat()?)?;
|
||||
let struct_field = self.infer.as_ref()?.record_field_pat_resolution(pat_id)?;
|
||||
Some(struct_field.into())
|
||||
}
|
||||
|
||||
pub(crate) fn resolve_macro_call(
|
||||
&self,
|
||||
db: &dyn HirDatabase,
|
||||
|
|
|
@ -127,6 +127,7 @@ pub struct InferenceResult {
|
|||
field_resolutions: FxHashMap<ExprId, StructFieldId>,
|
||||
/// For each field in record literal, records the field it resolves to.
|
||||
record_field_resolutions: FxHashMap<ExprId, StructFieldId>,
|
||||
record_field_pat_resolutions: FxHashMap<PatId, StructFieldId>,
|
||||
/// For each struct literal, records the variant it resolves to.
|
||||
variant_resolutions: FxHashMap<ExprOrPatId, VariantId>,
|
||||
/// For each associated item record what it resolves to
|
||||
|
@ -147,6 +148,9 @@ impl InferenceResult {
|
|||
pub fn record_field_resolution(&self, expr: ExprId) -> Option<StructFieldId> {
|
||||
self.record_field_resolutions.get(&expr).copied()
|
||||
}
|
||||
pub fn record_field_pat_resolution(&self, pat: PatId) -> Option<StructFieldId> {
|
||||
self.record_field_pat_resolutions.get(&pat).copied()
|
||||
}
|
||||
pub fn variant_resolution_for_expr(&self, id: ExprId) -> Option<VariantId> {
|
||||
self.variant_resolutions.get(&id.into()).copied()
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ use hir_def::{
|
|||
expr::{BindingAnnotation, Pat, PatId, RecordFieldPat},
|
||||
path::Path,
|
||||
type_ref::Mutability,
|
||||
StructFieldId,
|
||||
};
|
||||
use hir_expand::name::Name;
|
||||
use test_utils::tested_by;
|
||||
|
@ -67,6 +68,11 @@ impl<'a> InferenceContext<'a> {
|
|||
let field_tys = def.map(|it| self.db.field_types(it)).unwrap_or_default();
|
||||
for subpat in subpats {
|
||||
let matching_field = var_data.as_ref().and_then(|it| it.field(&subpat.name));
|
||||
if let Some(local_id) = matching_field {
|
||||
let field_def = StructFieldId { parent: def.unwrap(), local_id };
|
||||
self.result.record_field_pat_resolutions.insert(subpat.pat, field_def);
|
||||
}
|
||||
|
||||
let expected_ty =
|
||||
matching_field.map_or(Ty::Unknown, |field| field_tys[field].clone().subst(&substs));
|
||||
let expected_ty = self.normalize_associated_types_in(expected_ty);
|
||||
|
|
|
@ -62,10 +62,9 @@ pub(crate) enum ReferenceResult {
|
|||
|
||||
impl ReferenceResult {
|
||||
fn to_vec(self) -> Vec<NavigationTarget> {
|
||||
use self::ReferenceResult::*;
|
||||
match self {
|
||||
Exact(target) => vec![target],
|
||||
Approximate(vec) => vec,
|
||||
ReferenceResult::Exact(target) => vec![target],
|
||||
ReferenceResult::Approximate(vec) => vec,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -74,8 +73,6 @@ pub(crate) fn reference_definition(
|
|||
sema: &Semantics<RootDatabase>,
|
||||
name_ref: &ast::NameRef,
|
||||
) -> ReferenceResult {
|
||||
use self::ReferenceResult::*;
|
||||
|
||||
let name_kind = classify_name_ref(sema, name_ref);
|
||||
if let Some(def) = name_kind {
|
||||
let def = def.definition();
|
||||
|
@ -91,7 +88,7 @@ pub(crate) fn reference_definition(
|
|||
.into_iter()
|
||||
.map(|s| s.to_nav(sema.db))
|
||||
.collect();
|
||||
Approximate(navs)
|
||||
ReferenceResult::Approximate(navs)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
@ -398,6 +395,25 @@ mod tests {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn goto_def_for_record_pat_fields() {
|
||||
covers!(ra_ide_db::goto_def_for_record_field_pats);
|
||||
check_goto(
|
||||
r"
|
||||
//- /lib.rs
|
||||
struct Foo {
|
||||
spam: u32,
|
||||
}
|
||||
|
||||
fn bar(foo: Foo) -> Foo {
|
||||
let Foo { spam<|>: _, } = foo
|
||||
}
|
||||
",
|
||||
"spam RECORD_FIELD_DEF FileId(1) [17; 26) [17; 21)",
|
||||
"spam: u32|spam",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn goto_def_for_record_fields_macros() {
|
||||
check_goto(
|
||||
|
|
|
@ -180,6 +180,7 @@ fn classify_name_inner(sema: &Semantics<RootDatabase>, name: &ast::Name) -> Opti
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum NameRefClass {
|
||||
Definition(Definition),
|
||||
FieldShorthand { local: Local, field: Definition },
|
||||
|
@ -229,6 +230,14 @@ pub fn classify_name_ref(
|
|||
}
|
||||
}
|
||||
|
||||
if let Some(record_field_pat) = ast::RecordFieldPat::cast(parent.clone()) {
|
||||
tested_by!(goto_def_for_record_field_pats; force);
|
||||
if let Some(field) = sema.resolve_record_field_pat(&record_field_pat) {
|
||||
let field = Definition::StructField(field);
|
||||
return Some(NameRefClass::Definition(field));
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(macro_call) = parent.ancestors().find_map(ast::MacroCall::cast) {
|
||||
tested_by!(goto_def_for_macros; force);
|
||||
if let Some(macro_def) = sema.resolve_macro_call(¯o_call) {
|
||||
|
|
|
@ -6,5 +6,6 @@ test_utils::marks![
|
|||
goto_def_for_fields
|
||||
goto_def_for_record_fields
|
||||
goto_def_for_field_init_shorthand
|
||||
goto_def_for_record_field_pats
|
||||
search_filters_by_range
|
||||
];
|
||||
|
|
Loading…
Reference in a new issue