move function to defs.rs
This commit is contained in:
parent
18e6b508dd
commit
589c1dfa04
@ -1,6 +1,5 @@
|
||||
use std::convert::TryInto;
|
||||
|
||||
use crate::hover::find_definition;
|
||||
use crate::{
|
||||
display::TryToNav,
|
||||
doc_links::{doc_attributes, extract_definitions_from_docs, resolve_doc_path_for_def},
|
||||
@ -10,11 +9,11 @@
|
||||
use ide_db::{
|
||||
base_db::{AnchoredPath, FileId, FileLoader},
|
||||
defs::Definition,
|
||||
helpers::{pick_best_token, try_resolve_derive_input_at},
|
||||
helpers::pick_best_token,
|
||||
RootDatabase,
|
||||
};
|
||||
use itertools::Itertools;
|
||||
use syntax::{ast, match_ast, AstNode, AstToken, SyntaxKind::*, SyntaxToken, TextRange, T};
|
||||
use syntax::{ast, AstNode, AstToken, SyntaxKind::*, SyntaxToken, TextRange, T};
|
||||
|
||||
// Feature: Go to Definition
|
||||
//
|
||||
@ -57,22 +56,22 @@ pub(crate) fn goto_definition(
|
||||
.into_iter()
|
||||
.filter_map(|token| {
|
||||
let parent = token.parent()?;
|
||||
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::TokenTree(tt) =>
|
||||
try_lookup_include_path_or_derive(&sema, tt, token, position.file_id),
|
||||
_ => None
|
||||
if let Some(tt) = ast::TokenTree::cast(parent.clone()) {
|
||||
if let x @ Some(_) =
|
||||
try_lookup_include_path(&sema, tt, token.clone(), position.file_id)
|
||||
{
|
||||
return x;
|
||||
}
|
||||
}
|
||||
Some(
|
||||
Definition::from_node(&sema, &token)
|
||||
.into_iter()
|
||||
.flat_map(|def| {
|
||||
try_find_trait_item_definition(sema.db, &def)
|
||||
.unwrap_or_else(|| def_to_nav(sema.db, def))
|
||||
})
|
||||
.collect::<Vec<_>>(),
|
||||
)
|
||||
})
|
||||
.flatten()
|
||||
.unique()
|
||||
@ -81,41 +80,31 @@ pub(crate) fn goto_definition(
|
||||
Some(RangeInfo::new(original_token.text_range(), navs))
|
||||
}
|
||||
|
||||
fn try_lookup_include_path_or_derive(
|
||||
fn try_lookup_include_path(
|
||||
sema: &Semantics<RootDatabase>,
|
||||
tt: ast::TokenTree,
|
||||
token: SyntaxToken,
|
||||
file_id: FileId,
|
||||
) -> Option<Vec<NavigationTarget>> {
|
||||
match ast::String::cast(token.clone()) {
|
||||
Some(token) => {
|
||||
let path = token.value()?.into_owned();
|
||||
let macro_call = tt.syntax().parent().and_then(ast::MacroCall::cast)?;
|
||||
let name = macro_call.path()?.segment()?.name_ref()?;
|
||||
if !matches!(&*name.text(), "include" | "include_str" | "include_bytes") {
|
||||
return None;
|
||||
}
|
||||
let file_id = sema.db.resolve_path(AnchoredPath { anchor: file_id, path: &path })?;
|
||||
let size = sema.db.file_text(file_id).len().try_into().ok()?;
|
||||
Some(vec![NavigationTarget {
|
||||
file_id,
|
||||
full_range: TextRange::new(0.into(), size),
|
||||
name: path.into(),
|
||||
focus_range: None,
|
||||
kind: None,
|
||||
container_name: None,
|
||||
description: None,
|
||||
docs: None,
|
||||
}])
|
||||
}
|
||||
None => try_resolve_derive_input_at(
|
||||
sema,
|
||||
&tt.syntax().ancestors().nth(2).and_then(ast::Attr::cast)?,
|
||||
&token,
|
||||
)
|
||||
.and_then(|it| it.try_to_nav(sema.db))
|
||||
.map(|it| vec![it]),
|
||||
let token = ast::String::cast(token.clone())?;
|
||||
let path = token.value()?.into_owned();
|
||||
let macro_call = tt.syntax().parent().and_then(ast::MacroCall::cast)?;
|
||||
let name = macro_call.path()?.segment()?.name_ref()?;
|
||||
if !matches!(&*name.text(), "include" | "include_str" | "include_bytes") {
|
||||
return None;
|
||||
}
|
||||
let file_id = sema.db.resolve_path(AnchoredPath { anchor: file_id, path: &path })?;
|
||||
let size = sema.db.file_text(file_id).len().try_into().ok()?;
|
||||
Some(vec![NavigationTarget {
|
||||
file_id,
|
||||
full_range: TextRange::new(0.into(), size),
|
||||
name: path.into(),
|
||||
focus_range: None,
|
||||
kind: None,
|
||||
container_name: None,
|
||||
description: None,
|
||||
docs: None,
|
||||
}])
|
||||
}
|
||||
|
||||
/// finds the trait definition of an impl'd item
|
||||
|
@ -1,13 +1,13 @@
|
||||
use std::{collections::HashSet, iter, ops::ControlFlow};
|
||||
use std::{collections::HashSet, ops::ControlFlow};
|
||||
|
||||
use either::Either;
|
||||
use hir::{AsAssocItem, HasAttrs, HasSource, HirDisplay, Semantics, TypeInfo};
|
||||
use ide_db::{
|
||||
base_db::{FileRange, SourceDatabase},
|
||||
defs::{Definition, NameClass, NameRefClass},
|
||||
defs::Definition,
|
||||
helpers::{
|
||||
generated_lints::{CLIPPY_LINTS, DEFAULT_LINTS, FEATURES},
|
||||
pick_best_token, try_resolve_derive_input_at, FamousDefs,
|
||||
pick_best_token, FamousDefs,
|
||||
},
|
||||
RootDatabase,
|
||||
};
|
||||
@ -107,7 +107,7 @@ pub(crate) fn hover(
|
||||
}
|
||||
let offset = range.start();
|
||||
|
||||
let token = pick_best_token(file.token_at_offset(offset), |kind| match kind {
|
||||
let original_token = pick_best_token(file.token_at_offset(offset), |kind| match kind {
|
||||
IDENT | INT_NUMBER | LIFETIME_IDENT | T![self] | T![super] | T![crate] => 3,
|
||||
T!['('] | T![')'] => 2,
|
||||
kind if kind.is_trivia() => 0,
|
||||
@ -119,7 +119,7 @@ pub(crate) fn hover(
|
||||
let mut fallback = None;
|
||||
// attributes, require special machinery as they are mere ident tokens
|
||||
|
||||
let descend_macros = sema.descend_into_macros_many(token.clone());
|
||||
let descend_macros = sema.descend_into_macros_many(original_token.clone());
|
||||
|
||||
for token in &descend_macros {
|
||||
if token.kind() != COMMENT {
|
||||
@ -127,21 +127,6 @@ pub(crate) fn hover(
|
||||
// lints
|
||||
if let Some(res) = try_hover_for_lint(&attr, &token) {
|
||||
return Some(res);
|
||||
// derives
|
||||
} else {
|
||||
let def =
|
||||
try_resolve_derive_input_at(&sema, &attr, &token).map(Definition::Macro);
|
||||
if let Some(def) = def {
|
||||
if let Some(hover) = hover_for_definition(
|
||||
&sema,
|
||||
file_id,
|
||||
def,
|
||||
&token.parent().unwrap(),
|
||||
config,
|
||||
) {
|
||||
return Some(RangeInfo::new(token.text_range(), hover));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -151,7 +136,16 @@ pub(crate) fn hover(
|
||||
.iter()
|
||||
.filter_map(|token| match token.parent() {
|
||||
Some(node) => {
|
||||
match find_hover_result(&sema, file_id, offset, config, token, &node, &mut seen) {
|
||||
match find_hover_result(
|
||||
&sema,
|
||||
file_id,
|
||||
offset,
|
||||
config,
|
||||
&original_token,
|
||||
token,
|
||||
&node,
|
||||
&mut seen,
|
||||
) {
|
||||
Some(res) => match res {
|
||||
ControlFlow::Break(inner) => Some(inner),
|
||||
ControlFlow::Continue(_) => {
|
||||
@ -189,6 +183,7 @@ fn find_hover_result(
|
||||
file_id: FileId,
|
||||
offset: TextSize,
|
||||
config: &HoverConfig,
|
||||
original_token: &SyntaxToken,
|
||||
token: &SyntaxToken,
|
||||
node: &SyntaxNode,
|
||||
seen: &mut HashSet<Definition>,
|
||||
@ -199,7 +194,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).next().or_else(|| {
|
||||
let definition = Definition::from_node(sema, token).into_iter().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
|
||||
@ -242,7 +237,7 @@ fn find_hover_result(
|
||||
seen.insert(definition);
|
||||
}
|
||||
if let Some(res) = hover_for_definition(sema, file_id, definition, &node, config) {
|
||||
let range = range_override.unwrap_or_else(|| sema.original_range(&node).range);
|
||||
let range = range_override.unwrap_or_else(|| original_token.text_range());
|
||||
return Some(ControlFlow::Break(RangeInfo::new(range, res)));
|
||||
}
|
||||
}
|
||||
@ -724,53 +719,6 @@ 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<'a>(
|
||||
sema: &'a Semantics<RootDatabase>,
|
||||
node: &SyntaxNode,
|
||||
) -> 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)],
|
||||
}
|
||||
},
|
||||
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(
|
||||
sema: &Semantics<RootDatabase>,
|
||||
file_id: FileId,
|
||||
@ -4587,7 +4535,6 @@ mod bar {
|
||||
);
|
||||
}
|
||||
|
||||
// FIXME: wrong range in macros. `es! ` should be `Copy`
|
||||
#[test]
|
||||
fn hover_attribute_in_macro() {
|
||||
check(
|
||||
@ -4605,7 +4552,7 @@ macro_rules! identity {
|
||||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
*es! *
|
||||
*Copy*
|
||||
|
||||
```rust
|
||||
test
|
||||
|
@ -35,7 +35,7 @@ macro_rules! eprintln {
|
||||
mod goto_definition;
|
||||
mod goto_implementation;
|
||||
mod goto_type_definition;
|
||||
pub mod hover;
|
||||
mod hover;
|
||||
mod inlay_hints;
|
||||
mod join_lines;
|
||||
mod markdown_remove;
|
||||
|
@ -11,10 +11,10 @@
|
||||
};
|
||||
use syntax::{
|
||||
ast::{self, AstNode},
|
||||
match_ast, SyntaxKind,
|
||||
match_ast, SyntaxKind, SyntaxToken,
|
||||
};
|
||||
|
||||
use crate::RootDatabase;
|
||||
use crate::{helpers::try_resolve_derive_input_at, RootDatabase};
|
||||
|
||||
// FIXME: a more precise name would probably be `Symbol`?
|
||||
#[derive(Debug, PartialEq, Eq, Copy, Clone, Hash)]
|
||||
@ -29,6 +29,62 @@ pub enum Definition {
|
||||
}
|
||||
|
||||
impl Definition {
|
||||
pub fn from_node(sema: &Semantics<RootDatabase>, token: &SyntaxToken) -> Vec<Definition> {
|
||||
let node = if let Some(x) = token.parent() {
|
||||
x
|
||||
} else {
|
||||
return vec![];
|
||||
};
|
||||
if token.kind() != SyntaxKind::COMMENT {
|
||||
if let Some(attr) = token.ancestors().find_map(ast::Attr::cast) {
|
||||
// derives
|
||||
let def = try_resolve_derive_input_at(&sema, &attr, &token).map(Definition::Macro);
|
||||
if let Some(def) = def {
|
||||
return vec![def];
|
||||
}
|
||||
}
|
||||
}
|
||||
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)],
|
||||
}
|
||||
},
|
||||
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 fn module(&self, db: &RootDatabase) -> Option<Module> {
|
||||
match self {
|
||||
Definition::Macro(it) => it.module(db),
|
||||
|
Loading…
Reference in New Issue
Block a user