Simplify
This commit is contained in:
parent
b57289c4cb
commit
0ff380fe17
@ -1,7 +1,7 @@
|
|||||||
use hir::Semantics;
|
use hir::Semantics;
|
||||||
use ide_db::{
|
use ide_db::{
|
||||||
base_db::FilePosition,
|
base_db::{FileId, FilePosition},
|
||||||
defs::{Definition, NameClass, NameRefClass},
|
defs::Definition,
|
||||||
helpers::{for_each_break_expr, for_each_tail_expr, node_ext::walk_expr, pick_best_token},
|
helpers::{for_each_break_expr, for_each_tail_expr, node_ext::walk_expr, pick_best_token},
|
||||||
search::{FileReference, ReferenceCategory, SearchScope},
|
search::{FileReference, ReferenceCategory, SearchScope},
|
||||||
RootDatabase,
|
RootDatabase,
|
||||||
@ -11,7 +11,7 @@ use syntax::{
|
|||||||
ast::{self, HasLoopBody},
|
ast::{self, HasLoopBody},
|
||||||
match_ast, AstNode,
|
match_ast, AstNode,
|
||||||
SyntaxKind::IDENT,
|
SyntaxKind::IDENT,
|
||||||
SyntaxNode, SyntaxToken, TextRange, TextSize, T,
|
SyntaxNode, SyntaxToken, TextRange, T,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{display::TryToNav, references, NavigationTarget};
|
use crate::{display::TryToNav, references, NavigationTarget};
|
||||||
@ -45,12 +45,12 @@ pub struct HighlightRelatedConfig {
|
|||||||
pub(crate) fn highlight_related(
|
pub(crate) fn highlight_related(
|
||||||
sema: &Semantics<RootDatabase>,
|
sema: &Semantics<RootDatabase>,
|
||||||
config: HighlightRelatedConfig,
|
config: HighlightRelatedConfig,
|
||||||
position: FilePosition,
|
FilePosition { offset, file_id }: FilePosition,
|
||||||
) -> Option<Vec<HighlightedRange>> {
|
) -> Option<Vec<HighlightedRange>> {
|
||||||
let _p = profile::span("highlight_related");
|
let _p = profile::span("highlight_related");
|
||||||
let syntax = sema.parse(position.file_id).syntax().clone();
|
let syntax = sema.parse(file_id).syntax().clone();
|
||||||
|
|
||||||
let token = pick_best_token(syntax.token_at_offset(position.offset), |kind| match kind {
|
let token = pick_best_token(syntax.token_at_offset(offset), |kind| match kind {
|
||||||
T![?] => 4, // prefer `?` when the cursor is sandwiched like in `await$0?`
|
T![?] => 4, // prefer `?` when the cursor is sandwiched like in `await$0?`
|
||||||
T![->] => 3,
|
T![->] => 3,
|
||||||
kind if kind.is_keyword() => 2,
|
kind if kind.is_keyword() => 2,
|
||||||
@ -68,17 +68,18 @@ pub(crate) fn highlight_related(
|
|||||||
highlight_break_points(token)
|
highlight_break_points(token)
|
||||||
}
|
}
|
||||||
T![break] | T![loop] | T![while] if config.break_points => highlight_break_points(token),
|
T![break] | T![loop] | T![while] if config.break_points => highlight_break_points(token),
|
||||||
_ if config.references => highlight_references(sema, &syntax, position),
|
_ if config.references => highlight_references(sema, &syntax, token, file_id),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn highlight_references(
|
fn highlight_references(
|
||||||
sema: &Semantics<RootDatabase>,
|
sema: &Semantics<RootDatabase>,
|
||||||
syntax: &SyntaxNode,
|
node: &SyntaxNode,
|
||||||
FilePosition { offset, file_id }: FilePosition,
|
token: SyntaxToken,
|
||||||
|
file_id: FileId,
|
||||||
) -> Option<Vec<HighlightedRange>> {
|
) -> Option<Vec<HighlightedRange>> {
|
||||||
let defs = find_defs(sema, syntax, offset);
|
let defs = find_defs(sema, token.clone());
|
||||||
let usages = defs
|
let usages = defs
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|&d| {
|
.filter_map(|&d| {
|
||||||
@ -105,11 +106,8 @@ fn highlight_references(
|
|||||||
.filter(|decl| decl.file_id == file_id)
|
.filter(|decl| decl.file_id == file_id)
|
||||||
.and_then(|decl| {
|
.and_then(|decl| {
|
||||||
let range = decl.focus_range?;
|
let range = decl.focus_range?;
|
||||||
let category = if references::decl_mutability(&def, syntax, range) {
|
let category =
|
||||||
Some(ReferenceCategory::Write)
|
references::decl_mutability(&def, node, range).then(|| ReferenceCategory::Write);
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
Some(HighlightedRange { range, category })
|
Some(HighlightedRange { range, category })
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
@ -293,43 +291,10 @@ fn cover_range(r0: Option<TextRange>, r1: Option<TextRange>) -> Option<TextRange
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn find_defs(
|
fn find_defs(sema: &Semantics<RootDatabase>, token: SyntaxToken) -> FxHashSet<Definition> {
|
||||||
sema: &Semantics<RootDatabase>,
|
sema.descend_into_macros(token)
|
||||||
syntax: &SyntaxNode,
|
.into_iter()
|
||||||
offset: TextSize,
|
.flat_map(|token| Definition::from_token(sema, &token))
|
||||||
) -> FxHashSet<Definition> {
|
|
||||||
sema.find_nodes_at_offset_with_descend(syntax, offset)
|
|
||||||
.flat_map(|name_like| {
|
|
||||||
Some(match name_like {
|
|
||||||
ast::NameLike::NameRef(name_ref) => {
|
|
||||||
match NameRefClass::classify(sema, &name_ref)? {
|
|
||||||
NameRefClass::Definition(def) => vec![def],
|
|
||||||
NameRefClass::FieldShorthand { local_ref, field_ref } => {
|
|
||||||
vec![Definition::Local(local_ref), Definition::Field(field_ref)]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ast::NameLike::Name(name) => match NameClass::classify(sema, &name)? {
|
|
||||||
NameClass::Definition(it) | NameClass::ConstReference(it) => vec![it],
|
|
||||||
NameClass::PatFieldShorthand { local_def, field_ref } => {
|
|
||||||
vec![Definition::Local(local_def), Definition::Field(field_ref)]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
ast::NameLike::Lifetime(lifetime) => {
|
|
||||||
NameRefClass::classify_lifetime(sema, &lifetime)
|
|
||||||
.and_then(|class| match class {
|
|
||||||
NameRefClass::Definition(it) => Some(it),
|
|
||||||
_ => None,
|
|
||||||
})
|
|
||||||
.or_else(|| {
|
|
||||||
NameClass::classify_lifetime(sema, &lifetime)
|
|
||||||
.and_then(NameClass::defined)
|
|
||||||
})
|
|
||||||
.map(|it| vec![it])?
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
.flatten()
|
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,9 +9,6 @@
|
|||||||
//! at the index that the match starts at and its tree parent is
|
//! at the index that the match starts at and its tree parent is
|
||||||
//! resolved to the search element definition, we get a reference.
|
//! resolved to the search element definition, we get a reference.
|
||||||
|
|
||||||
use std::iter;
|
|
||||||
|
|
||||||
use either::Either;
|
|
||||||
use hir::{PathResolution, Semantics};
|
use hir::{PathResolution, Semantics};
|
||||||
use ide_db::{
|
use ide_db::{
|
||||||
base_db::FileId,
|
base_db::FileId,
|
||||||
@ -58,69 +55,67 @@ pub(crate) fn find_all_refs(
|
|||||||
) -> Option<Vec<ReferenceSearchResult>> {
|
) -> Option<Vec<ReferenceSearchResult>> {
|
||||||
let _p = profile::span("find_all_refs");
|
let _p = profile::span("find_all_refs");
|
||||||
let syntax = sema.parse(position.file_id).syntax().clone();
|
let syntax = sema.parse(position.file_id).syntax().clone();
|
||||||
|
let make_searcher = |literal_search: bool| {
|
||||||
|
move |def: Definition| {
|
||||||
|
let mut usages =
|
||||||
|
def.usages(sema).set_scope(search_scope.clone()).include_self_refs().all();
|
||||||
|
let declaration = match def {
|
||||||
|
Definition::Module(module) => {
|
||||||
|
Some(NavigationTarget::from_module_to_decl(sema.db, module))
|
||||||
|
}
|
||||||
|
def => def.try_to_nav(sema.db),
|
||||||
|
}
|
||||||
|
.map(|nav| {
|
||||||
|
let decl_range = nav.focus_or_full_range();
|
||||||
|
Declaration {
|
||||||
|
is_mut: decl_mutability(&def, sema.parse(nav.file_id).syntax(), decl_range),
|
||||||
|
nav,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if literal_search {
|
||||||
|
retain_adt_literal_usages(&mut usages, def, sema);
|
||||||
|
}
|
||||||
|
|
||||||
let mut is_literal_search = false;
|
let references = usages
|
||||||
let defs = match name_for_constructor_search(&syntax, position) {
|
.into_iter()
|
||||||
|
.map(|(file_id, refs)| {
|
||||||
|
(
|
||||||
|
file_id,
|
||||||
|
refs.into_iter()
|
||||||
|
.map(|file_ref| (file_ref.range, file_ref.category))
|
||||||
|
.collect(),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
ReferenceSearchResult { declaration, references }
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
match name_for_constructor_search(&syntax, position) {
|
||||||
Some(name) => {
|
Some(name) => {
|
||||||
is_literal_search = true;
|
|
||||||
let def = match NameClass::classify(sema, &name)? {
|
let def = match NameClass::classify(sema, &name)? {
|
||||||
NameClass::Definition(it) | NameClass::ConstReference(it) => it,
|
NameClass::Definition(it) | NameClass::ConstReference(it) => it,
|
||||||
NameClass::PatFieldShorthand { local_def: _, field_ref } => {
|
NameClass::PatFieldShorthand { local_def: _, field_ref } => {
|
||||||
Definition::Field(field_ref)
|
Definition::Field(field_ref)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
Either::Left(iter::once(def))
|
Some(vec![make_searcher(true)(def)])
|
||||||
}
|
}
|
||||||
None => Either::Right(find_defs(sema, &syntax, position.offset)),
|
None => {
|
||||||
};
|
let search = make_searcher(false);
|
||||||
|
Some(find_defs(sema, &syntax, position.offset).into_iter().map(search).collect())
|
||||||
Some(
|
}
|
||||||
defs.into_iter()
|
}
|
||||||
.map(|def| {
|
|
||||||
let mut usages =
|
|
||||||
def.usages(sema).set_scope(search_scope.clone()).include_self_refs().all();
|
|
||||||
let declaration = match def {
|
|
||||||
Definition::Module(module) => {
|
|
||||||
Some(NavigationTarget::from_module_to_decl(sema.db, module))
|
|
||||||
}
|
|
||||||
def => def.try_to_nav(sema.db),
|
|
||||||
}
|
|
||||||
.map(|nav| {
|
|
||||||
let decl_range = nav.focus_or_full_range();
|
|
||||||
Declaration {
|
|
||||||
is_mut: decl_mutability(&def, sema.parse(nav.file_id).syntax(), decl_range),
|
|
||||||
nav,
|
|
||||||
}
|
|
||||||
});
|
|
||||||
if is_literal_search {
|
|
||||||
retain_adt_literal_usages(&mut usages, def, sema);
|
|
||||||
}
|
|
||||||
|
|
||||||
let references = usages
|
|
||||||
.into_iter()
|
|
||||||
.map(|(file_id, refs)| {
|
|
||||||
(
|
|
||||||
file_id,
|
|
||||||
refs.into_iter()
|
|
||||||
.map(|file_ref| (file_ref.range, file_ref.category))
|
|
||||||
.collect(),
|
|
||||||
)
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
ReferenceSearchResult { declaration, references }
|
|
||||||
})
|
|
||||||
.collect(),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn find_defs<'a>(
|
fn find_defs<'a>(
|
||||||
sema: &'a Semantics<RootDatabase>,
|
sema: &'a Semantics<RootDatabase>,
|
||||||
syntax: &SyntaxNode,
|
syntax: &SyntaxNode,
|
||||||
offset: TextSize,
|
offset: TextSize,
|
||||||
) -> impl Iterator<Item = Definition> + 'a {
|
) -> impl Iterator<Item = Definition> + 'a {
|
||||||
sema.find_nodes_at_offset_with_descend(syntax, offset).filter_map(move |node| {
|
sema.find_nodes_at_offset_with_descend(syntax, offset).filter_map(move |name_like| {
|
||||||
Some(match node {
|
let def = match name_like {
|
||||||
ast::NameLike::NameRef(name_ref) => match NameRefClass::classify(sema, &name_ref)? {
|
ast::NameLike::NameRef(name_ref) => match NameRefClass::classify(sema, &name_ref)? {
|
||||||
NameRefClass::Definition(def) => def,
|
NameRefClass::Definition(def) => def,
|
||||||
NameRefClass::FieldShorthand { local_ref, field_ref: _ } => {
|
NameRefClass::FieldShorthand { local_ref, field_ref: _ } => {
|
||||||
@ -141,7 +136,8 @@ pub(crate) fn find_defs<'a>(
|
|||||||
.or_else(|| {
|
.or_else(|| {
|
||||||
NameClass::classify_lifetime(sema, &lifetime).and_then(NameClass::defined)
|
NameClass::classify_lifetime(sema, &lifetime).and_then(NameClass::defined)
|
||||||
})?,
|
})?,
|
||||||
})
|
};
|
||||||
|
Some(def)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -209,7 +209,7 @@ pub(crate) fn related_tests(
|
|||||||
|
|
||||||
find_related_tests(&sema, position, search_scope, &mut res);
|
find_related_tests(&sema, position, search_scope, &mut res);
|
||||||
|
|
||||||
res.into_iter().collect_vec()
|
res.into_iter().collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn find_related_tests(
|
fn find_related_tests(
|
||||||
@ -218,56 +218,59 @@ fn find_related_tests(
|
|||||||
search_scope: Option<SearchScope>,
|
search_scope: Option<SearchScope>,
|
||||||
tests: &mut FxHashSet<Runnable>,
|
tests: &mut FxHashSet<Runnable>,
|
||||||
) {
|
) {
|
||||||
if let Some(refs) = references::find_all_refs(sema, position, search_scope) {
|
let refs = match references::find_all_refs(sema, position, search_scope) {
|
||||||
for (file_id, refs) in refs.into_iter().flat_map(|refs| refs.references) {
|
Some(it) => it,
|
||||||
let file = sema.parse(file_id);
|
_ => return,
|
||||||
let file = file.syntax();
|
};
|
||||||
|
for (file_id, refs) in refs.into_iter().flat_map(|refs| refs.references) {
|
||||||
|
let file = sema.parse(file_id);
|
||||||
|
let file = file.syntax();
|
||||||
|
|
||||||
// create flattened vec of tokens
|
// create flattened vec of tokens
|
||||||
let tokens = refs.iter().flat_map(|(range, _)| {
|
let tokens =
|
||||||
match file.token_at_offset(range.start()).next() {
|
refs.iter().flat_map(|(range, _)| match file.token_at_offset(range.start()).next() {
|
||||||
Some(token) => sema.descend_into_macros(token),
|
Some(token) => sema.descend_into_macros(token),
|
||||||
None => Default::default(),
|
None => Default::default(),
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// find first suitable ancestor
|
// find first suitable ancestor
|
||||||
let functions = tokens
|
let functions = tokens
|
||||||
.filter_map(|token| token.ancestors().find_map(ast::Fn::cast))
|
.filter_map(|token| token.ancestors().find_map(ast::Fn::cast))
|
||||||
.map(|f| hir::InFile::new(sema.hir_file_for(f.syntax()), f));
|
.map(|f| hir::InFile::new(sema.hir_file_for(f.syntax()), f));
|
||||||
|
|
||||||
for fn_def in functions {
|
for InFile { value: fn_def, .. } in functions {
|
||||||
let InFile { value: fn_def, .. } = &fn_def;
|
if let Some(runnable) = as_test_runnable(sema, &fn_def) {
|
||||||
if let Some(runnable) = as_test_runnable(sema, fn_def) {
|
// direct test
|
||||||
// direct test
|
tests.insert(runnable);
|
||||||
tests.insert(runnable);
|
} else if let Some(module) = parent_test_module(sema, &fn_def) {
|
||||||
} else if let Some(module) = parent_test_module(sema, fn_def) {
|
// indirect test
|
||||||
// indirect test
|
find_related_tests_in_module(sema, &fn_def, &module, tests);
|
||||||
find_related_tests_in_module(sema, fn_def, &module, tests);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn find_related_tests_in_module(
|
fn find_related_tests_in_module(
|
||||||
sema: &Semantics<RootDatabase>,
|
sema: &Semantics<RootDatabase>,
|
||||||
fn_def: &ast::Fn,
|
fn_def: &ast::Fn,
|
||||||
parent_module: &hir::Module,
|
parent_module: &hir::Module,
|
||||||
tests: &mut FxHashSet<Runnable>,
|
tests: &mut FxHashSet<Runnable>,
|
||||||
) {
|
) {
|
||||||
if let Some(fn_name) = fn_def.name() {
|
let fn_name = match fn_def.name() {
|
||||||
let mod_source = parent_module.definition_source(sema.db);
|
Some(it) => it,
|
||||||
let range = match mod_source.value {
|
_ => return,
|
||||||
hir::ModuleSource::Module(m) => m.syntax().text_range(),
|
};
|
||||||
hir::ModuleSource::BlockExpr(b) => b.syntax().text_range(),
|
let mod_source = parent_module.definition_source(sema.db);
|
||||||
hir::ModuleSource::SourceFile(f) => f.syntax().text_range(),
|
let range = match &mod_source.value {
|
||||||
};
|
hir::ModuleSource::Module(m) => m.syntax().text_range(),
|
||||||
|
hir::ModuleSource::BlockExpr(b) => b.syntax().text_range(),
|
||||||
|
hir::ModuleSource::SourceFile(f) => f.syntax().text_range(),
|
||||||
|
};
|
||||||
|
|
||||||
let file_id = mod_source.file_id.original_file(sema.db);
|
let file_id = mod_source.file_id.original_file(sema.db);
|
||||||
let mod_scope = SearchScope::file_range(FileRange { file_id, range });
|
let mod_scope = SearchScope::file_range(FileRange { file_id, range });
|
||||||
let fn_pos = FilePosition { file_id, offset: fn_name.syntax().text_range().start() };
|
let fn_pos = FilePosition { file_id, offset: fn_name.syntax().text_range().start() };
|
||||||
find_related_tests(sema, fn_pos, Some(mod_scope), tests)
|
find_related_tests(sema, fn_pos, Some(mod_scope), tests)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn as_test_runnable(sema: &Semantics<RootDatabase>, fn_def: &ast::Fn) -> Option<Runnable> {
|
fn as_test_runnable(sema: &Semantics<RootDatabase>, fn_def: &ast::Fn) -> Option<Runnable> {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user