mirror of
https://github.com/rust-lang/rust-analyzer
synced 2025-01-28 04:45:05 +00:00
Fix resolve for field init shorthand
This commit is contained in:
parent
a0571359f3
commit
3d4b48e481
6 changed files with 68 additions and 36 deletions
|
@ -1,4 +1,6 @@
|
||||||
//! FIXME: write short doc here
|
//! Finds a corresponding hir data structure for a syntax node in a specific
|
||||||
|
//! file.
|
||||||
|
|
||||||
use hir_def::{
|
use hir_def::{
|
||||||
child_by_source::ChildBySource, dyn_map::DynMap, keys, keys::Key, nameres::ModuleSource,
|
child_by_source::ChildBySource, dyn_map::DynMap, keys, keys::Key, nameres::ModuleSource,
|
||||||
ConstId, DefWithBodyId, EnumId, EnumVariantId, FunctionId, GenericDefId, ImplId, ModuleId,
|
ConstId, DefWithBodyId, EnumId, EnumVariantId, FunctionId, GenericDefId, ImplId, ModuleId,
|
||||||
|
@ -11,14 +13,14 @@ use ra_syntax::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
db::{AstDatabase, DefDatabase, HirDatabase},
|
db::{DefDatabase, HirDatabase},
|
||||||
Const, DefWithBody, Enum, EnumVariant, FieldSource, Function, ImplBlock, InFile, Local,
|
Const, DefWithBody, Enum, EnumVariant, FieldSource, Function, ImplBlock, InFile, Local,
|
||||||
MacroDef, Module, Static, Struct, StructField, Trait, TypeAlias, TypeParam, Union,
|
MacroDef, Module, Static, Struct, StructField, Trait, TypeAlias, TypeParam, Union,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub trait FromSource: Sized {
|
pub trait FromSource: Sized {
|
||||||
type Ast;
|
type Ast;
|
||||||
fn from_source(db: &(impl DefDatabase + AstDatabase), src: InFile<Self::Ast>) -> Option<Self>;
|
fn from_source(db: &impl DefDatabase, src: InFile<Self::Ast>) -> Option<Self>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait FromSourceByContainer: Sized {
|
pub trait FromSourceByContainer: Sized {
|
||||||
|
@ -32,7 +34,7 @@ where
|
||||||
T: From<<T as FromSourceByContainer>::Id>,
|
T: From<<T as FromSourceByContainer>::Id>,
|
||||||
{
|
{
|
||||||
type Ast = <T as FromSourceByContainer>::Ast;
|
type Ast = <T as FromSourceByContainer>::Ast;
|
||||||
fn from_source(db: &(impl DefDatabase + AstDatabase), src: InFile<Self::Ast>) -> Option<Self> {
|
fn from_source(db: &impl DefDatabase, src: InFile<Self::Ast>) -> Option<Self> {
|
||||||
analyze_container(db, src.as_ref().map(|it| it.syntax()))[T::KEY]
|
analyze_container(db, src.as_ref().map(|it| it.syntax()))[T::KEY]
|
||||||
.get(&src)
|
.get(&src)
|
||||||
.copied()
|
.copied()
|
||||||
|
@ -64,7 +66,7 @@ from_source_by_container_impls![
|
||||||
|
|
||||||
impl FromSource for MacroDef {
|
impl FromSource for MacroDef {
|
||||||
type Ast = ast::MacroCall;
|
type Ast = ast::MacroCall;
|
||||||
fn from_source(db: &(impl DefDatabase + AstDatabase), src: InFile<Self::Ast>) -> Option<Self> {
|
fn from_source(db: &impl DefDatabase, src: InFile<Self::Ast>) -> Option<Self> {
|
||||||
let kind = MacroDefKind::Declarative;
|
let kind = MacroDefKind::Declarative;
|
||||||
|
|
||||||
let module_src = ModuleSource::from_child_node(db, src.as_ref().map(|it| it.syntax()));
|
let module_src = ModuleSource::from_child_node(db, src.as_ref().map(|it| it.syntax()));
|
||||||
|
@ -80,7 +82,7 @@ impl FromSource for MacroDef {
|
||||||
|
|
||||||
impl FromSource for EnumVariant {
|
impl FromSource for EnumVariant {
|
||||||
type Ast = ast::EnumVariant;
|
type Ast = ast::EnumVariant;
|
||||||
fn from_source(db: &(impl DefDatabase + AstDatabase), src: InFile<Self::Ast>) -> Option<Self> {
|
fn from_source(db: &impl DefDatabase, src: InFile<Self::Ast>) -> Option<Self> {
|
||||||
let parent_enum = src.value.parent_enum();
|
let parent_enum = src.value.parent_enum();
|
||||||
let src_enum = InFile { file_id: src.file_id, value: parent_enum };
|
let src_enum = InFile { file_id: src.file_id, value: parent_enum };
|
||||||
let parent_enum = Enum::from_source(db, src_enum)?;
|
let parent_enum = Enum::from_source(db, src_enum)?;
|
||||||
|
@ -93,7 +95,7 @@ impl FromSource for EnumVariant {
|
||||||
|
|
||||||
impl FromSource for StructField {
|
impl FromSource for StructField {
|
||||||
type Ast = FieldSource;
|
type Ast = FieldSource;
|
||||||
fn from_source(db: &(impl DefDatabase + AstDatabase), src: InFile<Self::Ast>) -> Option<Self> {
|
fn from_source(db: &impl DefDatabase, src: InFile<Self::Ast>) -> Option<Self> {
|
||||||
let src = src.as_ref();
|
let src = src.as_ref();
|
||||||
|
|
||||||
// FIXME this is buggy
|
// FIXME this is buggy
|
||||||
|
|
|
@ -237,7 +237,13 @@ impl SourceAnalyzer {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn resolve_record_field(&self, field: &ast::RecordField) -> Option<crate::StructField> {
|
pub fn resolve_record_field(&self, field: &ast::RecordField) -> Option<crate::StructField> {
|
||||||
let expr_id = self.expr_id(&field.expr()?)?;
|
let expr_id = match field.expr() {
|
||||||
|
Some(it) => self.expr_id(&it)?,
|
||||||
|
None => {
|
||||||
|
let src = InFile { file_id: self.file_id, value: field };
|
||||||
|
self.body_source_map.as_ref()?.field_init_shorthand_expr(src)?
|
||||||
|
}
|
||||||
|
};
|
||||||
self.infer.as_ref()?.record_field_resolution(expr_id).map(|it| it.into())
|
self.infer.as_ref()?.record_field_resolution(expr_id).map(|it| it.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -229,6 +229,11 @@ impl BodySourceMap {
|
||||||
self.expr_map.get(&src).cloned()
|
self.expr_map.get(&src).cloned()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn field_init_shorthand_expr(&self, node: InFile<&ast::RecordField>) -> Option<ExprId> {
|
||||||
|
let src = node.map(|it| Either::Right(AstPtr::new(it)));
|
||||||
|
self.expr_map.get(&src).cloned()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn pat_syntax(&self, pat: PatId) -> Option<PatSource> {
|
pub fn pat_syntax(&self, pat: PatId) -> Option<PatSource> {
|
||||||
self.pat_map_back.get(pat).copied()
|
self.pat_map_back.get(pat).copied()
|
||||||
}
|
}
|
||||||
|
|
|
@ -258,7 +258,7 @@ mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn goto_definition_works_in_items() {
|
fn goto_def_in_items() {
|
||||||
check_goto(
|
check_goto(
|
||||||
"
|
"
|
||||||
//- /lib.rs
|
//- /lib.rs
|
||||||
|
@ -271,7 +271,7 @@ mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn goto_definition_works_at_start_of_item() {
|
fn goto_def_at_start_of_item() {
|
||||||
check_goto(
|
check_goto(
|
||||||
"
|
"
|
||||||
//- /lib.rs
|
//- /lib.rs
|
||||||
|
@ -305,7 +305,7 @@ mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn goto_definition_works_for_module_declaration() {
|
fn goto_def_for_module_declaration() {
|
||||||
check_goto(
|
check_goto(
|
||||||
"
|
"
|
||||||
//- /lib.rs
|
//- /lib.rs
|
||||||
|
@ -332,8 +332,8 @@ mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn goto_definition_works_for_macros() {
|
fn goto_def_for_macros() {
|
||||||
covers!(goto_definition_works_for_macros);
|
covers!(goto_def_for_macros);
|
||||||
check_goto(
|
check_goto(
|
||||||
"
|
"
|
||||||
//- /lib.rs
|
//- /lib.rs
|
||||||
|
@ -349,8 +349,8 @@ mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn goto_definition_works_for_macros_from_other_crates() {
|
fn goto_def_for_macros_from_other_crates() {
|
||||||
covers!(goto_definition_works_for_macros);
|
covers!(goto_def_for_macros);
|
||||||
check_goto(
|
check_goto(
|
||||||
"
|
"
|
||||||
//- /lib.rs
|
//- /lib.rs
|
||||||
|
@ -369,7 +369,7 @@ mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn goto_definition_works_for_macros_in_use_tree() {
|
fn goto_def_for_macros_in_use_tree() {
|
||||||
check_goto(
|
check_goto(
|
||||||
"
|
"
|
||||||
//- /lib.rs
|
//- /lib.rs
|
||||||
|
@ -385,7 +385,7 @@ mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn goto_definition_works_for_macro_defined_fn_with_arg() {
|
fn goto_def_for_macro_defined_fn_with_arg() {
|
||||||
check_goto(
|
check_goto(
|
||||||
"
|
"
|
||||||
//- /lib.rs
|
//- /lib.rs
|
||||||
|
@ -405,7 +405,7 @@ mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn goto_definition_works_for_macro_defined_fn_no_arg() {
|
fn goto_def_for_macro_defined_fn_no_arg() {
|
||||||
check_goto(
|
check_goto(
|
||||||
"
|
"
|
||||||
//- /lib.rs
|
//- /lib.rs
|
||||||
|
@ -425,8 +425,8 @@ mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn goto_definition_works_for_methods() {
|
fn goto_def_for_methods() {
|
||||||
covers!(goto_definition_works_for_methods);
|
covers!(goto_def_for_methods);
|
||||||
check_goto(
|
check_goto(
|
||||||
"
|
"
|
||||||
//- /lib.rs
|
//- /lib.rs
|
||||||
|
@ -445,8 +445,8 @@ mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn goto_definition_works_for_fields() {
|
fn goto_def_for_fields() {
|
||||||
covers!(goto_definition_works_for_fields);
|
covers!(goto_def_for_fields);
|
||||||
check_goto(
|
check_goto(
|
||||||
"
|
"
|
||||||
//- /lib.rs
|
//- /lib.rs
|
||||||
|
@ -464,8 +464,8 @@ mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn goto_definition_works_for_record_fields() {
|
fn goto_def_for_record_fields() {
|
||||||
covers!(goto_definition_works_for_record_fields);
|
covers!(goto_def_for_record_fields);
|
||||||
check_goto(
|
check_goto(
|
||||||
"
|
"
|
||||||
//- /lib.rs
|
//- /lib.rs
|
||||||
|
@ -502,7 +502,7 @@ mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn goto_definition_works_for_ufcs_inherent_methods() {
|
fn goto_def_for_ufcs_inherent_methods() {
|
||||||
check_goto(
|
check_goto(
|
||||||
"
|
"
|
||||||
//- /lib.rs
|
//- /lib.rs
|
||||||
|
@ -521,7 +521,7 @@ mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn goto_definition_works_for_ufcs_trait_methods_through_traits() {
|
fn goto_def_for_ufcs_trait_methods_through_traits() {
|
||||||
check_goto(
|
check_goto(
|
||||||
"
|
"
|
||||||
//- /lib.rs
|
//- /lib.rs
|
||||||
|
@ -539,7 +539,7 @@ mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn goto_definition_works_for_ufcs_trait_methods_through_self() {
|
fn goto_def_for_ufcs_trait_methods_through_self() {
|
||||||
check_goto(
|
check_goto(
|
||||||
"
|
"
|
||||||
//- /lib.rs
|
//- /lib.rs
|
||||||
|
@ -654,7 +654,7 @@ mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn goto_definition_works_when_used_on_definition_name_itself() {
|
fn goto_def_when_used_on_definition_name_itself() {
|
||||||
check_goto(
|
check_goto(
|
||||||
"
|
"
|
||||||
//- /lib.rs
|
//- /lib.rs
|
||||||
|
@ -875,4 +875,21 @@ mod tests {
|
||||||
"x",
|
"x",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn goto_def_for_field_init_shorthand() {
|
||||||
|
covers!(goto_def_for_field_init_shorthand);
|
||||||
|
check_goto(
|
||||||
|
"
|
||||||
|
//- /lib.rs
|
||||||
|
struct Foo { x: i32 }
|
||||||
|
fn main() {
|
||||||
|
let x = 92;
|
||||||
|
Foo { x<|> };
|
||||||
|
}
|
||||||
|
",
|
||||||
|
"x RECORD_FIELD_DEF FileId(1) [13; 19) [13; 14)",
|
||||||
|
"x: i32|x",
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,10 +3,11 @@
|
||||||
test_utils::marks!(
|
test_utils::marks!(
|
||||||
inserts_angle_brackets_for_generics
|
inserts_angle_brackets_for_generics
|
||||||
inserts_parens_for_function_calls
|
inserts_parens_for_function_calls
|
||||||
goto_definition_works_for_macros
|
goto_def_for_macros
|
||||||
goto_definition_works_for_methods
|
goto_def_for_methods
|
||||||
goto_definition_works_for_fields
|
goto_def_for_fields
|
||||||
goto_definition_works_for_record_fields
|
goto_def_for_record_fields
|
||||||
|
goto_def_for_field_init_shorthand
|
||||||
call_info_bad_offset
|
call_info_bad_offset
|
||||||
dont_complete_current_use
|
dont_complete_current_use
|
||||||
dont_complete_primitive_in_use
|
dont_complete_primitive_in_use
|
||||||
|
|
|
@ -134,21 +134,22 @@ pub(crate) fn classify_name_ref(
|
||||||
let analyzer = SourceAnalyzer::new(db, name_ref.map(|it| it.syntax()), None);
|
let analyzer = SourceAnalyzer::new(db, name_ref.map(|it| it.syntax()), None);
|
||||||
|
|
||||||
if let Some(method_call) = ast::MethodCallExpr::cast(parent.clone()) {
|
if let Some(method_call) = ast::MethodCallExpr::cast(parent.clone()) {
|
||||||
tested_by!(goto_definition_works_for_methods);
|
tested_by!(goto_def_for_methods);
|
||||||
if let Some(func) = analyzer.resolve_method_call(&method_call) {
|
if let Some(func) = analyzer.resolve_method_call(&method_call) {
|
||||||
return Some(from_assoc_item(db, func.into()));
|
return Some(from_assoc_item(db, func.into()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(field_expr) = ast::FieldExpr::cast(parent.clone()) {
|
if let Some(field_expr) = ast::FieldExpr::cast(parent.clone()) {
|
||||||
tested_by!(goto_definition_works_for_fields);
|
tested_by!(goto_def_for_fields);
|
||||||
if let Some(field) = analyzer.resolve_field(&field_expr) {
|
if let Some(field) = analyzer.resolve_field(&field_expr) {
|
||||||
return Some(from_struct_field(db, field));
|
return Some(from_struct_field(db, field));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(record_field) = ast::RecordField::cast(parent.clone()) {
|
if let Some(record_field) = ast::RecordField::cast(parent.clone()) {
|
||||||
tested_by!(goto_definition_works_for_record_fields);
|
tested_by!(goto_def_for_record_fields);
|
||||||
|
tested_by!(goto_def_for_field_init_shorthand);
|
||||||
if let Some(field_def) = analyzer.resolve_record_field(&record_field) {
|
if let Some(field_def) = analyzer.resolve_record_field(&record_field) {
|
||||||
return Some(from_struct_field(db, field_def));
|
return Some(from_struct_field(db, field_def));
|
||||||
}
|
}
|
||||||
|
@ -160,7 +161,7 @@ pub(crate) fn classify_name_ref(
|
||||||
let visibility = None;
|
let visibility = None;
|
||||||
|
|
||||||
if let Some(macro_call) = parent.ancestors().find_map(ast::MacroCall::cast) {
|
if let Some(macro_call) = parent.ancestors().find_map(ast::MacroCall::cast) {
|
||||||
tested_by!(goto_definition_works_for_macros);
|
tested_by!(goto_def_for_macros);
|
||||||
if let Some(macro_def) = analyzer.resolve_macro_call(db, name_ref.with_value(¯o_call)) {
|
if let Some(macro_def) = analyzer.resolve_macro_call(db, name_ref.with_value(¯o_call)) {
|
||||||
let kind = NameKind::Macro(macro_def);
|
let kind = NameKind::Macro(macro_def);
|
||||||
return Some(NameDefinition { kind, container, visibility });
|
return Some(NameDefinition { kind, container, visibility });
|
||||||
|
|
Loading…
Reference in a new issue