mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-11-15 09:27:27 +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 hir::Semantics;
|
||||
use ide_db::call_info::FnCallNode;
|
||||
use ide_db::RootDatabase;
|
||||
use ide_db::{call_info::FnCallNode, RootDatabase};
|
||||
use syntax::{ast, AstNode, TextRange};
|
||||
|
||||
use crate::{
|
||||
|
|
|
@ -16,11 +16,10 @@ use hir::{
|
|||
};
|
||||
use ide_db::{
|
||||
defs::{Definition, NameClass, NameRefClass},
|
||||
helpers::pick_best_token,
|
||||
RootDatabase,
|
||||
};
|
||||
use syntax::{
|
||||
ast, match_ast, AstNode, SyntaxKind::*, SyntaxNode, SyntaxToken, TextRange, TokenAtOffset, T,
|
||||
};
|
||||
use syntax::{ast, match_ast, AstNode, SyntaxKind::*, SyntaxNode, TextRange, T};
|
||||
|
||||
use crate::{FilePosition, Semantics};
|
||||
|
||||
|
@ -102,7 +101,12 @@ pub(crate) fn external_docs(
|
|||
) -> Option<DocumentationLink> {
|
||||
let sema = Semantics::new(db);
|
||||
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 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)]
|
||||
mod tests {
|
||||
use expect_test::{expect, Expect};
|
||||
|
|
|
@ -1,11 +1,8 @@
|
|||
use std::iter;
|
||||
|
||||
use hir::Semantics;
|
||||
use ide_db::RootDatabase;
|
||||
use syntax::{
|
||||
ast, ted, AstNode, NodeOrToken, SyntaxKind, SyntaxKind::*, SyntaxNode, SyntaxToken,
|
||||
TokenAtOffset, WalkEvent, T,
|
||||
};
|
||||
use ide_db::{helpers::pick_best_token, RootDatabase};
|
||||
use syntax::{ast, ted, AstNode, NodeOrToken, SyntaxKind, SyntaxKind::*, SyntaxNode, WalkEvent, T};
|
||||
|
||||
use crate::FilePosition;
|
||||
|
||||
|
@ -29,7 +26,10 @@ pub(crate) fn expand_macro(db: &RootDatabase, position: FilePosition) -> Option<
|
|||
let sema = Semantics::new(db);
|
||||
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 name = None;
|
||||
for node in tok.ancestors() {
|
||||
|
@ -57,16 +57,6 @@ pub(crate) fn expand_macro(db: &RootDatabase, position: FilePosition) -> Option<
|
|||
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(
|
||||
sema: &Semantics<RootDatabase>,
|
||||
macro_call: &ast::MacroCall,
|
||||
|
|
|
@ -5,11 +5,10 @@ use hir::{AsAssocItem, InFile, ModuleDef, Semantics};
|
|||
use ide_db::{
|
||||
base_db::{AnchoredPath, FileId, FileLoader},
|
||||
defs::{Definition, NameClass, NameRefClass},
|
||||
helpers::pick_best_token,
|
||||
RootDatabase,
|
||||
};
|
||||
use syntax::{
|
||||
ast, match_ast, AstNode, AstToken, SyntaxKind::*, SyntaxToken, TextRange, TokenAtOffset, T,
|
||||
};
|
||||
use syntax::{ast, match_ast, AstNode, AstToken, SyntaxKind::*, SyntaxToken, TextRange, T};
|
||||
|
||||
use crate::{
|
||||
display::TryToNav,
|
||||
|
@ -34,7 +33,12 @@ pub(crate) fn goto_definition(
|
|||
) -> Option<RangeInfo<Vec<NavigationTarget>>> {
|
||||
let sema = Semantics::new(db);
|
||||
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 parent = token.parent()?;
|
||||
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())
|
||||
}
|
||||
|
||||
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(
|
||||
sema: &Semantics<RootDatabase>,
|
||||
name_ref: Either<&ast::Lifetime, &ast::NameRef>,
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
use ide_db::base_db::Upcast;
|
||||
use ide_db::helpers::pick_best_token;
|
||||
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};
|
||||
|
||||
|
@ -22,7 +23,12 @@ pub(crate) fn goto_type_definition(
|
|||
let sema = hir::Semantics::new(db);
|
||||
|
||||
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 (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]))
|
||||
}
|
||||
|
||||
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)]
|
||||
mod tests {
|
||||
use ide_db::base_db::FileRange;
|
||||
|
|
|
@ -5,16 +5,13 @@ use ide_db::{
|
|||
defs::{Definition, NameClass, NameRefClass},
|
||||
helpers::{
|
||||
generated_lints::{CLIPPY_LINTS, DEFAULT_LINTS, FEATURES},
|
||||
FamousDefs,
|
||||
pick_best_token, FamousDefs,
|
||||
},
|
||||
RootDatabase,
|
||||
};
|
||||
use itertools::Itertools;
|
||||
use stdx::format_to;
|
||||
use syntax::{
|
||||
algo, ast, match_ast, AstNode, AstToken, Direction, SyntaxKind::*, SyntaxToken, TokenAtOffset,
|
||||
T,
|
||||
};
|
||||
use syntax::{algo, ast, match_ast, AstNode, AstToken, Direction, SyntaxKind::*, SyntaxToken, T};
|
||||
|
||||
use crate::{
|
||||
display::{macro_label, TryToNav},
|
||||
|
@ -80,7 +77,12 @@ pub(crate) fn hover(
|
|||
) -> Option<RangeInfo<HoverResult>> {
|
||||
let sema = hir::Semantics::new(db);
|
||||
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 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))
|
||||
}
|
||||
|
||||
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)]
|
||||
mod tests {
|
||||
use expect_test::{expect, Expect};
|
||||
|
|
|
@ -439,7 +439,7 @@ impl Analysis {
|
|||
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>>> {
|
||||
self.with_db(|db| call_hierarchy::outgoing_calls(db, position))
|
||||
}
|
||||
|
|
|
@ -1,12 +1,9 @@
|
|||
use std::{iter::once, mem};
|
||||
|
||||
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 syntax::{
|
||||
algo, ast, match_ast, AstNode, SyntaxElement, SyntaxKind, SyntaxNode, SyntaxToken, TextRange,
|
||||
TokenAtOffset,
|
||||
};
|
||||
use syntax::{algo, ast, match_ast, AstNode, SyntaxElement, SyntaxKind, SyntaxNode, TextRange};
|
||||
use text_edit::{TextEdit, TextEditBuilder};
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
|
@ -36,7 +33,14 @@ pub(crate) fn move_item(
|
|||
let file = sema.parse(range.file_id);
|
||||
|
||||
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 {
|
||||
file.syntax().covering_element(range.range)
|
||||
};
|
||||
|
@ -170,18 +174,6 @@ fn replace_nodes<'a>(
|
|||
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)]
|
||||
mod tests {
|
||||
use crate::fixture;
|
||||
|
|
|
@ -10,7 +10,10 @@ use std::collections::VecDeque;
|
|||
use base_db::FileId;
|
||||
use either::Either;
|
||||
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;
|
||||
|
||||
|
@ -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.
|
||||
pub fn mod_path_to_ast(path: &hir::ModPath) -> ast::Path {
|
||||
let _p = profile::span("mod_path_to_ast");
|
||||
|
|
Loading…
Reference in a new issue