use find_definition in go to

This commit is contained in:
hamidreza kalbasi 2021-09-22 11:37:26 +03:30
parent 887b7ddc37
commit 569ac5bee1
3 changed files with 64 additions and 64 deletions

View File

@ -1,5 +1,11 @@
use std::{convert::TryInto, iter};
use crate::hover::find_definition;
use crate::{
display::{ToNav, TryToNav},
doc_links::{doc_attributes, extract_definitions_from_docs, resolve_doc_path_for_def},
FilePosition, NavigationTarget, RangeInfo,
};
use either::Either;
use hir::{AsAssocItem, InFile, ModuleDef, Semantics};
use ide_db::{
@ -11,12 +17,6 @@ use ide_db::{
use itertools::Itertools;
use syntax::{ast, match_ast, AstNode, AstToken, SyntaxKind::*, SyntaxToken, TextRange, T};
use crate::{
display::{ToNav, TryToNav},
doc_links::{doc_attributes, extract_definitions_from_docs, resolve_doc_path_for_def},
FilePosition, NavigationTarget, RangeInfo,
};
// Feature: Go to Definition
//
// Navigates to the definition of an identifier.
@ -58,39 +58,22 @@ pub(crate) fn goto_definition(
.into_iter()
.filter_map(|token| {
let parent = token.parent()?;
let navs = match_ast! {
let result = find_definition(&sema, &parent)
.flat_map(|def| {
try_find_trait_item_definition(sema.db, &def)
.unwrap_or_else(|| def_to_nav(sema.db, def))
})
.collect::<Vec<_>>();
if !result.is_empty() {
return Some(result);
}
match_ast! {
match parent {
ast::NameRef(name_ref) => {
reference_definition(&sema, Either::Right(&name_ref))
},
ast::Name(name) => {
match NameClass::classify(&sema, &name)? {
NameClass::Definition(def) | NameClass::ConstReference(def) => {
try_find_trait_item_definition(sema.db, &def)
.unwrap_or_else(|| def_to_nav(sema.db, def))
}
NameClass::PatFieldShorthand { local_def, field_ref } => {
local_and_field_to_nav(sema.db, local_def, field_ref)
},
}
},
ast::Lifetime(lt) => {
match NameClass::classify_lifetime(&sema, &lt) {
Some(name_class) => {
match name_class {
NameClass::Definition(def) => def_to_nav(sema.db, def),
_ => return None,
}
}
None => reference_definition(&sema, Either::Left(&lt)),
}
},
ast::TokenTree(tt) =>
try_lookup_include_path_or_derive(&sema, tt, token, position.file_id)?,
_ => return None,
try_lookup_include_path_or_derive(&sema, tt, token, position.file_id),
_ => None
}
};
Some(navs)
}
})
.flatten()
.unique()

View File

@ -1,4 +1,4 @@
use std::{collections::HashSet, ops::ControlFlow};
use std::{collections::HashSet, iter, ops::ControlFlow};
use either::Either;
use hir::{AsAssocItem, HasAttrs, HasSource, HirDisplay, Semantics, TypeInfo};
@ -199,7 +199,7 @@ fn find_hover_result(
// so don't add them to the `seen` duplicate check
let mut add_to_seen_definitions = true;
let definition = find_definition(sema, node).or_else(|| {
let definition = find_definition(sema, node).next().or_else(|| {
// intra-doc links
// FIXME: move comment + attribute special cases somewhere else to simplify control flow,
// hopefully simplifying the return type of this function in the process
@ -724,34 +724,51 @@ fn definition_mod_path(db: &RootDatabase, def: &Definition) -> Option<String> {
def.module(db).map(|module| render_path(db, module, definition_owner_name(db, def)))
}
pub(crate) fn find_definition(
sema: &Semantics<RootDatabase>,
pub(crate) fn find_definition<'a>(
sema: &'a Semantics<RootDatabase>,
node: &SyntaxNode,
) -> Option<Definition> {
match_ast! {
match node {
ast::Name(name) => NameClass::classify(sema, &name).map(|class| match class {
NameClass::Definition(it) | NameClass::ConstReference(it) => it,
NameClass::PatFieldShorthand { local_def, field_ref: _ } => Definition::Local(local_def),
}),
ast::NameRef(name_ref) => NameRefClass::classify(sema, &name_ref).map(|class| match class {
NameRefClass::Definition(def) => def,
NameRefClass::FieldShorthand { local_ref: _, field_ref } => {
Definition::Field(field_ref)
}
}),
ast::Lifetime(lifetime) => NameClass::classify_lifetime(&sema, &lifetime).map_or_else(
|| {
NameRefClass::classify_lifetime(&sema, &lifetime).and_then(|class| match class {
NameRefClass::Definition(it) => Some(it),
_ => None,
})
) -> impl Iterator<Item = Definition> + 'a {
iter::once(node.clone()).flat_map(move |node| {
match_ast! {
match node {
ast::Name(name) => {
let class = if let Some(x) = NameClass::classify(&sema, &name) {
x
} else {
return vec![];
};
match class {
NameClass::Definition(it) | NameClass::ConstReference(it) => vec![it],
NameClass::PatFieldShorthand { local_def, field_ref } => vec![Definition::Local(local_def), Definition::Field(field_ref)],
}
},
NameClass::defined,
),
_ => None,
ast::NameRef(name_ref) => {
let class = if let Some(x) = NameRefClass::classify(sema, &name_ref) {
x
} else {
return vec![];
};
match class {
NameRefClass::Definition(def) => vec![def],
NameRefClass::FieldShorthand { local_ref, field_ref } => {
vec![Definition::Field(field_ref), Definition::Local(local_ref)]
}
}
},
ast::Lifetime(lifetime) => {
(if let Some(x) = NameClass::classify_lifetime(&sema, &lifetime) {
NameClass::defined(x)
} else {
NameRefClass::classify_lifetime(&sema, &lifetime).and_then(|class| match class {
NameRefClass::Definition(it) => Some(it),
_ => None,
})
}).into_iter().collect()
},
_ => vec![],
}
}
}
})
}
pub(crate) fn hover_for_definition(

View File

@ -35,7 +35,7 @@ mod goto_declaration;
mod goto_definition;
mod goto_implementation;
mod goto_type_definition;
mod hover;
pub mod hover;
mod inlay_hints;
mod join_lines;
mod markdown_remove;