mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-27 12:29:21 +00:00
Factor out pick_best_token
ide pattern into ide_db
This commit is contained in:
parent
4e2ec914f4
commit
f615efdfc3
9 changed files with 62 additions and 101 deletions
|
@ -3,8 +3,7 @@
|
||||||
use indexmap::IndexMap;
|
use indexmap::IndexMap;
|
||||||
|
|
||||||
use hir::Semantics;
|
use hir::Semantics;
|
||||||
use ide_db::call_info::FnCallNode;
|
use ide_db::{call_info::FnCallNode, RootDatabase};
|
||||||
use ide_db::RootDatabase;
|
|
||||||
use syntax::{ast, AstNode, TextRange};
|
use syntax::{ast, AstNode, TextRange};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
|
|
@ -16,11 +16,10 @@ use hir::{
|
||||||
};
|
};
|
||||||
use ide_db::{
|
use ide_db::{
|
||||||
defs::{Definition, NameClass, NameRefClass},
|
defs::{Definition, NameClass, NameRefClass},
|
||||||
|
helpers::pick_best_token,
|
||||||
RootDatabase,
|
RootDatabase,
|
||||||
};
|
};
|
||||||
use syntax::{
|
use syntax::{ast, match_ast, AstNode, SyntaxKind::*, SyntaxNode, TextRange, T};
|
||||||
ast, match_ast, AstNode, SyntaxKind::*, SyntaxNode, SyntaxToken, TextRange, TokenAtOffset, T,
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::{FilePosition, Semantics};
|
use crate::{FilePosition, Semantics};
|
||||||
|
|
||||||
|
@ -102,7 +101,12 @@ pub(crate) fn external_docs(
|
||||||
) -> Option<DocumentationLink> {
|
) -> Option<DocumentationLink> {
|
||||||
let sema = Semantics::new(db);
|
let sema = Semantics::new(db);
|
||||||
let file = sema.parse(position.file_id).syntax().clone();
|
let file = sema.parse(position.file_id).syntax().clone();
|
||||||
let token = pick_best(file.token_at_offset(position.offset))?;
|
let token = pick_best_token(file.token_at_offset(position.offset), |kind| match kind {
|
||||||
|
IDENT | INT_NUMBER => 3,
|
||||||
|
T!['('] | T![')'] => 2,
|
||||||
|
kind if kind.is_trivia() => 0,
|
||||||
|
_ => 1,
|
||||||
|
})?;
|
||||||
let token = sema.descend_into_macros(token);
|
let token = sema.descend_into_macros(token);
|
||||||
|
|
||||||
let node = token.parent()?;
|
let node = token.parent()?;
|
||||||
|
@ -522,18 +526,6 @@ fn get_symbol_fragment(db: &dyn HirDatabase, field_or_assoc: &FieldOrAssocItem)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pick_best(tokens: TokenAtOffset<SyntaxToken>) -> Option<SyntaxToken> {
|
|
||||||
return tokens.max_by_key(priority);
|
|
||||||
fn priority(n: &SyntaxToken) -> usize {
|
|
||||||
match n.kind() {
|
|
||||||
IDENT | INT_NUMBER => 3,
|
|
||||||
T!['('] | T![')'] => 2,
|
|
||||||
kind if kind.is_trivia() => 0,
|
|
||||||
_ => 1,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use expect_test::{expect, Expect};
|
use expect_test::{expect, Expect};
|
||||||
|
|
|
@ -1,11 +1,8 @@
|
||||||
use std::iter;
|
use std::iter;
|
||||||
|
|
||||||
use hir::Semantics;
|
use hir::Semantics;
|
||||||
use ide_db::RootDatabase;
|
use ide_db::{helpers::pick_best_token, RootDatabase};
|
||||||
use syntax::{
|
use syntax::{ast, ted, AstNode, NodeOrToken, SyntaxKind, SyntaxKind::*, SyntaxNode, WalkEvent, T};
|
||||||
ast, ted, AstNode, NodeOrToken, SyntaxKind, SyntaxKind::*, SyntaxNode, SyntaxToken,
|
|
||||||
TokenAtOffset, WalkEvent, T,
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::FilePosition;
|
use crate::FilePosition;
|
||||||
|
|
||||||
|
@ -29,7 +26,10 @@ pub(crate) fn expand_macro(db: &RootDatabase, position: FilePosition) -> Option<
|
||||||
let sema = Semantics::new(db);
|
let sema = Semantics::new(db);
|
||||||
let file = sema.parse(position.file_id);
|
let file = sema.parse(position.file_id);
|
||||||
|
|
||||||
let tok = pick_best(file.syntax().token_at_offset(position.offset))?;
|
let tok = pick_best_token(file.syntax().token_at_offset(position.offset), |kind| match kind {
|
||||||
|
SyntaxKind::IDENT => 1,
|
||||||
|
_ => 0,
|
||||||
|
})?;
|
||||||
let mut expanded = None;
|
let mut expanded = None;
|
||||||
let mut name = None;
|
let mut name = None;
|
||||||
for node in tok.ancestors() {
|
for node in tok.ancestors() {
|
||||||
|
@ -57,16 +57,6 @@ pub(crate) fn expand_macro(db: &RootDatabase, position: FilePosition) -> Option<
|
||||||
Some(ExpandedMacro { name: name?, expansion })
|
Some(ExpandedMacro { name: name?, expansion })
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pick_best(tokens: TokenAtOffset<SyntaxToken>) -> Option<SyntaxToken> {
|
|
||||||
return tokens.max_by_key(priority);
|
|
||||||
fn priority(n: &SyntaxToken) -> usize {
|
|
||||||
match n.kind() {
|
|
||||||
IDENT => 1,
|
|
||||||
_ => 0,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn expand_macro_recur(
|
fn expand_macro_recur(
|
||||||
sema: &Semantics<RootDatabase>,
|
sema: &Semantics<RootDatabase>,
|
||||||
macro_call: &ast::MacroCall,
|
macro_call: &ast::MacroCall,
|
||||||
|
|
|
@ -5,11 +5,10 @@ use hir::{AsAssocItem, InFile, ModuleDef, Semantics};
|
||||||
use ide_db::{
|
use ide_db::{
|
||||||
base_db::{AnchoredPath, FileId, FileLoader},
|
base_db::{AnchoredPath, FileId, FileLoader},
|
||||||
defs::{Definition, NameClass, NameRefClass},
|
defs::{Definition, NameClass, NameRefClass},
|
||||||
|
helpers::pick_best_token,
|
||||||
RootDatabase,
|
RootDatabase,
|
||||||
};
|
};
|
||||||
use syntax::{
|
use syntax::{ast, match_ast, AstNode, AstToken, SyntaxKind::*, SyntaxToken, TextRange, T};
|
||||||
ast, match_ast, AstNode, AstToken, SyntaxKind::*, SyntaxToken, TextRange, TokenAtOffset, T,
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
display::TryToNav,
|
display::TryToNav,
|
||||||
|
@ -34,7 +33,12 @@ pub(crate) fn goto_definition(
|
||||||
) -> Option<RangeInfo<Vec<NavigationTarget>>> {
|
) -> Option<RangeInfo<Vec<NavigationTarget>>> {
|
||||||
let sema = Semantics::new(db);
|
let sema = Semantics::new(db);
|
||||||
let file = sema.parse(position.file_id).syntax().clone();
|
let file = sema.parse(position.file_id).syntax().clone();
|
||||||
let original_token = pick_best(file.token_at_offset(position.offset))?;
|
let original_token =
|
||||||
|
pick_best_token(file.token_at_offset(position.offset), |kind| match kind {
|
||||||
|
IDENT | INT_NUMBER | LIFETIME_IDENT | T![self] | COMMENT => 2,
|
||||||
|
kind if kind.is_trivia() => 0,
|
||||||
|
_ => 1,
|
||||||
|
})?;
|
||||||
let token = sema.descend_into_macros(original_token.clone());
|
let token = sema.descend_into_macros(original_token.clone());
|
||||||
let parent = token.parent()?;
|
let parent = token.parent()?;
|
||||||
if let Some(_) = ast::Comment::cast(token.clone()) {
|
if let Some(_) = ast::Comment::cast(token.clone()) {
|
||||||
|
@ -128,17 +132,6 @@ fn try_find_trait_item_definition(db: &RootDatabase, def: &Definition) -> Option
|
||||||
.find_map(|itm| (itm.name(db)? == name).then(|| itm.try_to_nav(db)).flatten())
|
.find_map(|itm| (itm.name(db)? == name).then(|| itm.try_to_nav(db)).flatten())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pick_best(tokens: TokenAtOffset<SyntaxToken>) -> Option<SyntaxToken> {
|
|
||||||
return tokens.max_by_key(priority);
|
|
||||||
fn priority(n: &SyntaxToken) -> usize {
|
|
||||||
match n.kind() {
|
|
||||||
IDENT | INT_NUMBER | LIFETIME_IDENT | T![self] | COMMENT => 2,
|
|
||||||
kind if kind.is_trivia() => 0,
|
|
||||||
_ => 1,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn reference_definition(
|
pub(crate) fn reference_definition(
|
||||||
sema: &Semantics<RootDatabase>,
|
sema: &Semantics<RootDatabase>,
|
||||||
name_ref: Either<&ast::Lifetime, &ast::NameRef>,
|
name_ref: Either<&ast::Lifetime, &ast::NameRef>,
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
use ide_db::base_db::Upcast;
|
use ide_db::base_db::Upcast;
|
||||||
|
use ide_db::helpers::pick_best_token;
|
||||||
use ide_db::RootDatabase;
|
use ide_db::RootDatabase;
|
||||||
use syntax::{ast, match_ast, AstNode, SyntaxKind::*, SyntaxToken, TokenAtOffset, T};
|
use syntax::{ast, match_ast, AstNode, SyntaxKind::*, SyntaxToken, T};
|
||||||
|
|
||||||
use crate::{display::TryToNav, FilePosition, NavigationTarget, RangeInfo};
|
use crate::{display::TryToNav, FilePosition, NavigationTarget, RangeInfo};
|
||||||
|
|
||||||
|
@ -22,7 +23,12 @@ pub(crate) fn goto_type_definition(
|
||||||
let sema = hir::Semantics::new(db);
|
let sema = hir::Semantics::new(db);
|
||||||
|
|
||||||
let file: ast::SourceFile = sema.parse(position.file_id);
|
let file: ast::SourceFile = sema.parse(position.file_id);
|
||||||
let token: SyntaxToken = pick_best(file.syntax().token_at_offset(position.offset))?;
|
let token: SyntaxToken =
|
||||||
|
pick_best_token(file.syntax().token_at_offset(position.offset), |kind| match kind {
|
||||||
|
IDENT | INT_NUMBER | T![self] => 2,
|
||||||
|
kind if kind.is_trivia() => 0,
|
||||||
|
_ => 1,
|
||||||
|
})?;
|
||||||
let token: SyntaxToken = sema.descend_into_macros(token);
|
let token: SyntaxToken = sema.descend_into_macros(token);
|
||||||
|
|
||||||
let (ty, node) = sema.token_ancestors_with_macros(token).find_map(|node| {
|
let (ty, node) = sema.token_ancestors_with_macros(token).find_map(|node| {
|
||||||
|
@ -56,17 +62,6 @@ pub(crate) fn goto_type_definition(
|
||||||
Some(RangeInfo::new(node.text_range(), vec![nav]))
|
Some(RangeInfo::new(node.text_range(), vec![nav]))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pick_best(tokens: TokenAtOffset<SyntaxToken>) -> Option<SyntaxToken> {
|
|
||||||
return tokens.max_by_key(priority);
|
|
||||||
fn priority(n: &SyntaxToken) -> usize {
|
|
||||||
match n.kind() {
|
|
||||||
IDENT | INT_NUMBER | T![self] => 2,
|
|
||||||
kind if kind.is_trivia() => 0,
|
|
||||||
_ => 1,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use ide_db::base_db::FileRange;
|
use ide_db::base_db::FileRange;
|
||||||
|
|
|
@ -5,16 +5,13 @@ use ide_db::{
|
||||||
defs::{Definition, NameClass, NameRefClass},
|
defs::{Definition, NameClass, NameRefClass},
|
||||||
helpers::{
|
helpers::{
|
||||||
generated_lints::{CLIPPY_LINTS, DEFAULT_LINTS, FEATURES},
|
generated_lints::{CLIPPY_LINTS, DEFAULT_LINTS, FEATURES},
|
||||||
FamousDefs,
|
pick_best_token, FamousDefs,
|
||||||
},
|
},
|
||||||
RootDatabase,
|
RootDatabase,
|
||||||
};
|
};
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use stdx::format_to;
|
use stdx::format_to;
|
||||||
use syntax::{
|
use syntax::{algo, ast, match_ast, AstNode, AstToken, Direction, SyntaxKind::*, SyntaxToken, T};
|
||||||
algo, ast, match_ast, AstNode, AstToken, Direction, SyntaxKind::*, SyntaxToken, TokenAtOffset,
|
|
||||||
T,
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
display::{macro_label, TryToNav},
|
display::{macro_label, TryToNav},
|
||||||
|
@ -80,7 +77,12 @@ pub(crate) fn hover(
|
||||||
) -> Option<RangeInfo<HoverResult>> {
|
) -> Option<RangeInfo<HoverResult>> {
|
||||||
let sema = hir::Semantics::new(db);
|
let sema = hir::Semantics::new(db);
|
||||||
let file = sema.parse(position.file_id).syntax().clone();
|
let file = sema.parse(position.file_id).syntax().clone();
|
||||||
let token = pick_best(file.token_at_offset(position.offset))?;
|
let token = pick_best_token(file.token_at_offset(position.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,
|
||||||
|
_ => 1,
|
||||||
|
})?;
|
||||||
let token = sema.descend_into_macros(token);
|
let token = sema.descend_into_macros(token);
|
||||||
|
|
||||||
let mut res = HoverResult::default();
|
let mut res = HoverResult::default();
|
||||||
|
@ -519,19 +521,6 @@ fn find_std_module(famous_defs: &FamousDefs, name: &str) -> Option<hir::Module>
|
||||||
.find(|module| module.name(db).map_or(false, |module| module.to_string() == name))
|
.find(|module| module.name(db).map_or(false, |module| module.to_string() == name))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pick_best(tokens: TokenAtOffset<SyntaxToken>) -> Option<SyntaxToken> {
|
|
||||||
return tokens.max_by_key(priority);
|
|
||||||
|
|
||||||
fn priority(n: &SyntaxToken) -> usize {
|
|
||||||
match n.kind() {
|
|
||||||
IDENT | INT_NUMBER | LIFETIME_IDENT | T![self] | T![super] | T![crate] => 3,
|
|
||||||
T!['('] | T![')'] => 2,
|
|
||||||
kind if kind.is_trivia() => 0,
|
|
||||||
_ => 1,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use expect_test::{expect, Expect};
|
use expect_test::{expect, Expect};
|
||||||
|
|
|
@ -439,7 +439,7 @@ impl Analysis {
|
||||||
self.with_db(|db| call_hierarchy::incoming_calls(db, position))
|
self.with_db(|db| call_hierarchy::incoming_calls(db, position))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Computes incoming calls for the given file position.
|
/// Computes outgoing calls for the given file position.
|
||||||
pub fn outgoing_calls(&self, position: FilePosition) -> Cancellable<Option<Vec<CallItem>>> {
|
pub fn outgoing_calls(&self, position: FilePosition) -> Cancellable<Option<Vec<CallItem>>> {
|
||||||
self.with_db(|db| call_hierarchy::outgoing_calls(db, position))
|
self.with_db(|db| call_hierarchy::outgoing_calls(db, position))
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,9 @@
|
||||||
use std::{iter::once, mem};
|
use std::{iter::once, mem};
|
||||||
|
|
||||||
use hir::Semantics;
|
use hir::Semantics;
|
||||||
use ide_db::{base_db::FileRange, RootDatabase};
|
use ide_db::{base_db::FileRange, helpers::pick_best_token, RootDatabase};
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use syntax::{
|
use syntax::{algo, ast, match_ast, AstNode, SyntaxElement, SyntaxKind, SyntaxNode, TextRange};
|
||||||
algo, ast, match_ast, AstNode, SyntaxElement, SyntaxKind, SyntaxNode, SyntaxToken, TextRange,
|
|
||||||
TokenAtOffset,
|
|
||||||
};
|
|
||||||
use text_edit::{TextEdit, TextEditBuilder};
|
use text_edit::{TextEdit, TextEditBuilder};
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Copy, Clone, Debug)]
|
||||||
|
@ -36,7 +33,14 @@ pub(crate) fn move_item(
|
||||||
let file = sema.parse(range.file_id);
|
let file = sema.parse(range.file_id);
|
||||||
|
|
||||||
let item = if range.range.is_empty() {
|
let item = if range.range.is_empty() {
|
||||||
SyntaxElement::Token(pick_best(file.syntax().token_at_offset(range.range.start()))?)
|
SyntaxElement::Token(pick_best_token(
|
||||||
|
file.syntax().token_at_offset(range.range.start()),
|
||||||
|
|kind| match kind {
|
||||||
|
SyntaxKind::IDENT | SyntaxKind::LIFETIME_IDENT => 2,
|
||||||
|
kind if kind.is_trivia() => 0,
|
||||||
|
_ => 1,
|
||||||
|
},
|
||||||
|
)?)
|
||||||
} else {
|
} else {
|
||||||
file.syntax().covering_element(range.range)
|
file.syntax().covering_element(range.range)
|
||||||
};
|
};
|
||||||
|
@ -170,18 +174,6 @@ fn replace_nodes<'a>(
|
||||||
edit.finish()
|
edit.finish()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pick_best(tokens: TokenAtOffset<SyntaxToken>) -> Option<SyntaxToken> {
|
|
||||||
return tokens.max_by_key(priority);
|
|
||||||
|
|
||||||
fn priority(n: &SyntaxToken) -> usize {
|
|
||||||
match n.kind() {
|
|
||||||
SyntaxKind::IDENT | SyntaxKind::LIFETIME_IDENT => 2,
|
|
||||||
kind if kind.is_trivia() => 0,
|
|
||||||
_ => 1,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::fixture;
|
use crate::fixture;
|
||||||
|
|
|
@ -10,7 +10,10 @@ use std::collections::VecDeque;
|
||||||
use base_db::FileId;
|
use base_db::FileId;
|
||||||
use either::Either;
|
use either::Either;
|
||||||
use hir::{Crate, Enum, ItemInNs, MacroDef, Module, ModuleDef, Name, ScopeDef, Semantics, Trait};
|
use hir::{Crate, Enum, ItemInNs, MacroDef, Module, ModuleDef, Name, ScopeDef, Semantics, Trait};
|
||||||
use syntax::ast::{self, make};
|
use syntax::{
|
||||||
|
ast::{self, make},
|
||||||
|
SyntaxKind, SyntaxToken, TokenAtOffset,
|
||||||
|
};
|
||||||
|
|
||||||
use crate::RootDatabase;
|
use crate::RootDatabase;
|
||||||
|
|
||||||
|
@ -22,6 +25,14 @@ pub fn item_name(db: &RootDatabase, item: ItemInNs) -> Option<Name> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Picks the token with the highest rank returned by the passed in function.
|
||||||
|
pub fn pick_best_token(
|
||||||
|
tokens: TokenAtOffset<SyntaxToken>,
|
||||||
|
f: impl Fn(SyntaxKind) -> usize,
|
||||||
|
) -> Option<SyntaxToken> {
|
||||||
|
tokens.max_by_key(move |t| f(t.kind()))
|
||||||
|
}
|
||||||
|
|
||||||
/// Converts the mod path struct into its ast representation.
|
/// Converts the mod path struct into its ast representation.
|
||||||
pub fn mod_path_to_ast(path: &hir::ModPath) -> ast::Path {
|
pub fn mod_path_to_ast(path: &hir::ModPath) -> ast::Path {
|
||||||
let _p = profile::span("mod_path_to_ast");
|
let _p = profile::span("mod_path_to_ast");
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue