Factor out pick_best_token ide pattern into ide_db

This commit is contained in:
Lukas Wirth 2021-06-22 17:28:07 +02:00
parent 4e2ec914f4
commit f615efdfc3
9 changed files with 62 additions and 101 deletions

View file

@ -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::{

View file

@ -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};

View file

@ -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,

View file

@ -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>,

View file

@ -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;

View file

@ -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};

View file

@ -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))
}

View file

@ -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;

View file

@ -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");