mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-09 20:06:28 +00:00
Goto definition works for S { a: }
case
What happens here is that we lower `: ` to a missing expression, and then correctly record that the corresponding field expression resolves to a specific field. Where we fail is in the mapping of syntax to this missing expression. Doing it via `ast_field.expr()` fails, as that expression is `None`. Instead, we go in the opposite direcition and ask each lowered field about its source. This works, but has wrong complexity `O(N)` and, really, the implementation is just too complex. We need some better management of data here.
This commit is contained in:
parent
5138baf2ac
commit
af2366acdf
2 changed files with 33 additions and 3 deletions
|
@ -24,7 +24,7 @@ use hir_ty::{
|
||||||
};
|
};
|
||||||
use syntax::{
|
use syntax::{
|
||||||
ast::{self, AstNode},
|
ast::{self, AstNode},
|
||||||
SyntaxNode, TextRange, TextSize,
|
AstPtr, SyntaxNode, TextRange, TextSize,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
@ -161,8 +161,27 @@ impl SourceAnalyzer {
|
||||||
db: &dyn HirDatabase,
|
db: &dyn HirDatabase,
|
||||||
field: &ast::RecordExprField,
|
field: &ast::RecordExprField,
|
||||||
) -> Option<(Field, Option<Local>)> {
|
) -> Option<(Field, Option<Local>)> {
|
||||||
let expr = field.expr()?;
|
let expr_id = {
|
||||||
let expr_id = self.expr_id(db, &expr)?;
|
let record_lit = field.parent_record_lit();
|
||||||
|
let record_lit_expr = self.expr_id(db, &ast::Expr::from(record_lit))?;
|
||||||
|
let body = self.body.as_ref()?;
|
||||||
|
let body_source_map = self.body_source_map.as_ref()?;
|
||||||
|
match &body[record_lit_expr] {
|
||||||
|
hir_def::expr::Expr::RecordLit { fields, .. } => {
|
||||||
|
let field_ptr = InFile::new(self.file_id, AstPtr::new(field));
|
||||||
|
fields.iter().enumerate().find_map(|(i, f)| {
|
||||||
|
let ptr = body_source_map.field_syntax(record_lit_expr, i);
|
||||||
|
if ptr == field_ptr {
|
||||||
|
Some(f.expr)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
})?
|
||||||
|
}
|
||||||
|
_ => return None,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
let local = if field.name_ref().is_some() {
|
let local = if field.name_ref().is_some() {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -1158,6 +1158,17 @@ struct S;
|
||||||
|
|
||||||
//- /m.rs
|
//- /m.rs
|
||||||
//! [`super::S$0`]
|
//! [`super::S$0`]
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn goto_incomplete_field() {
|
||||||
|
check(
|
||||||
|
r#"
|
||||||
|
struct A { a: u32 }
|
||||||
|
//^
|
||||||
|
fn foo() { A { a$0: }; }
|
||||||
"#,
|
"#,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue