aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLukas Wirth <[email protected]>2021-01-11 23:05:07 +0000
committerLukas Wirth <[email protected]>2021-01-12 00:03:04 +0000
commitfbdb32adfc49e0d69b7fd8e44135bea59382d2cb (patch)
tree5cffb6d3f0a0a168bfa48d7adcd6fa233e30b3db
parent52fa926f005890f07dffc789c84c2be57a6bdccc (diff)
Group references by FileId
-rw-r--r--crates/assists/src/handlers/extract_struct_from_enum_variant.rs59
-rw-r--r--crates/assists/src/handlers/inline_local_variable.rs95
-rw-r--r--crates/assists/src/handlers/remove_unused_param.rs43
-rw-r--r--crates/ide/src/call_hierarchy.rs31
-rw-r--r--crates/ide/src/lib.rs2
-rw-r--r--crates/ide/src/references.rs98
-rw-r--r--crates/ide/src/references/rename.rs94
-rw-r--r--crates/ide_db/src/search.rs101
-rw-r--r--crates/rust-analyzer/src/handlers.rs33
-rw-r--r--crates/ssr/src/search.rs24
10 files changed, 324 insertions, 256 deletions
diff --git a/crates/assists/src/handlers/extract_struct_from_enum_variant.rs b/crates/assists/src/handlers/extract_struct_from_enum_variant.rs
index 40028fc01..21b13977b 100644
--- a/crates/assists/src/handlers/extract_struct_from_enum_variant.rs
+++ b/crates/assists/src/handlers/extract_struct_from_enum_variant.rs
@@ -2,12 +2,16 @@ use std::iter;
2 2
3use either::Either; 3use either::Either;
4use hir::{AsName, Module, ModuleDef, Name, Variant}; 4use hir::{AsName, Module, ModuleDef, Name, Variant};
5use ide_db::helpers::{ 5use ide_db::{
6 insert_use::{insert_use, ImportScope}, 6 defs::Definition,
7 mod_path_to_ast, 7 helpers::{
8 insert_use::{insert_use, ImportScope},
9 mod_path_to_ast,
10 },
11 search::{FileReference, FileReferences},
12 RootDatabase,
8}; 13};
9use ide_db::{defs::Definition, search::Reference, RootDatabase}; 14use rustc_hash::FxHashSet;
10use rustc_hash::{FxHashMap, FxHashSet};
11use syntax::{ 15use syntax::{
12 algo::{find_node_at_offset, SyntaxRewriter}, 16 algo::{find_node_at_offset, SyntaxRewriter},
13 ast::{self, edit::IndentLevel, make, AstNode, NameOwner, VisibilityOwner}, 17 ast::{self, edit::IndentLevel, make, AstNode, NameOwner, VisibilityOwner},
@@ -58,29 +62,29 @@ pub(crate) fn extract_struct_from_enum_variant(
58 let mut visited_modules_set = FxHashSet::default(); 62 let mut visited_modules_set = FxHashSet::default();
59 let current_module = enum_hir.module(ctx.db()); 63 let current_module = enum_hir.module(ctx.db());
60 visited_modules_set.insert(current_module); 64 visited_modules_set.insert(current_module);
61 let mut rewriters = FxHashMap::default(); 65 let mut def_rewriter = None;
62 for reference in usages { 66 for FileReferences { file_id, references: refs } in usages {
63 let rewriter = rewriters 67 let mut rewriter = SyntaxRewriter::default();
64 .entry(reference.file_range.file_id) 68 let source_file = ctx.sema.parse(file_id);
65 .or_insert_with(SyntaxRewriter::default); 69 for reference in refs {
66 let source_file = ctx.sema.parse(reference.file_range.file_id); 70 update_reference(
67 update_reference( 71 ctx,
68 ctx, 72 &mut rewriter,
69 rewriter, 73 reference,
70 reference, 74 &source_file,
71 &source_file, 75 &enum_module_def,
72 &enum_module_def, 76 &variant_hir_name,
73 &variant_hir_name, 77 &mut visited_modules_set,
74 &mut visited_modules_set, 78 );
75 ); 79 }
76 } 80 if file_id == ctx.frange.file_id {
77 let mut rewriter = 81 def_rewriter = Some(rewriter);
78 rewriters.remove(&ctx.frange.file_id).unwrap_or_else(SyntaxRewriter::default); 82 continue;
79 for (file_id, rewriter) in rewriters { 83 }
80 builder.edit_file(file_id); 84 builder.edit_file(file_id);
81 builder.rewrite(rewriter); 85 builder.rewrite(rewriter);
82 } 86 }
83 builder.edit_file(ctx.frange.file_id); 87 let mut rewriter = def_rewriter.unwrap_or_default();
84 update_variant(&mut rewriter, &variant); 88 update_variant(&mut rewriter, &variant);
85 extract_struct_def( 89 extract_struct_def(
86 &mut rewriter, 90 &mut rewriter,
@@ -90,6 +94,7 @@ pub(crate) fn extract_struct_from_enum_variant(
90 &variant.parent_enum().syntax().clone().into(), 94 &variant.parent_enum().syntax().clone().into(),
91 enum_ast.visibility(), 95 enum_ast.visibility(),
92 ); 96 );
97 builder.edit_file(ctx.frange.file_id);
93 builder.rewrite(rewriter); 98 builder.rewrite(rewriter);
94 }, 99 },
95 ) 100 )
@@ -205,13 +210,13 @@ fn update_variant(rewriter: &mut SyntaxRewriter, variant: &ast::Variant) -> Opti
205fn update_reference( 210fn update_reference(
206 ctx: &AssistContext, 211 ctx: &AssistContext,
207 rewriter: &mut SyntaxRewriter, 212 rewriter: &mut SyntaxRewriter,
208 reference: Reference, 213 reference: FileReference,
209 source_file: &SourceFile, 214 source_file: &SourceFile,
210 enum_module_def: &ModuleDef, 215 enum_module_def: &ModuleDef,
211 variant_hir_name: &Name, 216 variant_hir_name: &Name,
212 visited_modules_set: &mut FxHashSet<Module>, 217 visited_modules_set: &mut FxHashSet<Module>,
213) -> Option<()> { 218) -> Option<()> {
214 let offset = reference.file_range.range.start(); 219 let offset = reference.range.start();
215 let (segment, expr) = if let Some(path_expr) = 220 let (segment, expr) = if let Some(path_expr) =
216 find_node_at_offset::<ast::PathExpr>(source_file.syntax(), offset) 221 find_node_at_offset::<ast::PathExpr>(source_file.syntax(), offset)
217 { 222 {
diff --git a/crates/assists/src/handlers/inline_local_variable.rs b/crates/assists/src/handlers/inline_local_variable.rs
index d559be9cb..928df6825 100644
--- a/crates/assists/src/handlers/inline_local_variable.rs
+++ b/crates/assists/src/handlers/inline_local_variable.rs
@@ -1,4 +1,7 @@
1use ide_db::{defs::Definition, search::ReferenceKind}; 1use ide_db::{
2 defs::Definition,
3 search::{FileReference, ReferenceKind},
4};
2use syntax::{ 5use syntax::{
3 ast::{self, AstNode, AstToken}, 6 ast::{self, AstNode, AstToken},
4 TextRange, 7 TextRange,
@@ -63,48 +66,44 @@ pub(crate) fn inline_local_variable(acc: &mut Assists, ctx: &AssistContext) -> O
63 let_stmt.syntax().text_range() 66 let_stmt.syntax().text_range()
64 }; 67 };
65 68
66 let mut wrap_in_parens = vec![true; refs.len()]; 69 let wrap_in_parens = refs
67 70 .iter()
68 for (i, desc) in refs.iter().enumerate() { 71 .flat_map(|refs| &refs.references)
69 let usage_node = ctx 72 .map(|&FileReference { range, .. }| {
70 .covering_node_for_range(desc.file_range.range) 73 let usage_node =
71 .ancestors() 74 ctx.covering_node_for_range(range).ancestors().find_map(ast::PathExpr::cast)?;
72 .find_map(ast::PathExpr::cast)?; 75 let usage_parent_option = usage_node.syntax().parent().and_then(ast::Expr::cast);
73 let usage_parent_option = usage_node.syntax().parent().and_then(ast::Expr::cast); 76 let usage_parent = match usage_parent_option {
74 let usage_parent = match usage_parent_option { 77 Some(u) => u,
75 Some(u) => u, 78 None => return Ok(false),
76 None => { 79 };
77 wrap_in_parens[i] = false; 80
78 continue; 81 Ok(!matches!((&initializer_expr, usage_parent),
79 } 82 (ast::Expr::CallExpr(_), _)
80 }; 83 | (ast::Expr::IndexExpr(_), _)
81 84 | (ast::Expr::MethodCallExpr(_), _)
82 wrap_in_parens[i] = match (&initializer_expr, usage_parent) { 85 | (ast::Expr::FieldExpr(_), _)
83 (ast::Expr::CallExpr(_), _) 86 | (ast::Expr::TryExpr(_), _)
84 | (ast::Expr::IndexExpr(_), _) 87 | (ast::Expr::RefExpr(_), _)
85 | (ast::Expr::MethodCallExpr(_), _) 88 | (ast::Expr::Literal(_), _)
86 | (ast::Expr::FieldExpr(_), _) 89 | (ast::Expr::TupleExpr(_), _)
87 | (ast::Expr::TryExpr(_), _) 90 | (ast::Expr::ArrayExpr(_), _)
88 | (ast::Expr::RefExpr(_), _) 91 | (ast::Expr::ParenExpr(_), _)
89 | (ast::Expr::Literal(_), _) 92 | (ast::Expr::PathExpr(_), _)
90 | (ast::Expr::TupleExpr(_), _) 93 | (ast::Expr::BlockExpr(_), _)
91 | (ast::Expr::ArrayExpr(_), _) 94 | (ast::Expr::EffectExpr(_), _)
92 | (ast::Expr::ParenExpr(_), _) 95 | (_, ast::Expr::CallExpr(_))
93 | (ast::Expr::PathExpr(_), _) 96 | (_, ast::Expr::TupleExpr(_))
94 | (ast::Expr::BlockExpr(_), _) 97 | (_, ast::Expr::ArrayExpr(_))
95 | (ast::Expr::EffectExpr(_), _) 98 | (_, ast::Expr::ParenExpr(_))
96 | (_, ast::Expr::CallExpr(_)) 99 | (_, ast::Expr::ForExpr(_))
97 | (_, ast::Expr::TupleExpr(_)) 100 | (_, ast::Expr::WhileExpr(_))
98 | (_, ast::Expr::ArrayExpr(_)) 101 | (_, ast::Expr::BreakExpr(_))
99 | (_, ast::Expr::ParenExpr(_)) 102 | (_, ast::Expr::ReturnExpr(_))
100 | (_, ast::Expr::ForExpr(_)) 103 | (_, ast::Expr::MatchExpr(_))
101 | (_, ast::Expr::WhileExpr(_)) 104 ))
102 | (_, ast::Expr::BreakExpr(_)) 105 })
103 | (_, ast::Expr::ReturnExpr(_)) 106 .collect::<Result<Vec<_>, _>>()?;
104 | (_, ast::Expr::MatchExpr(_)) => false,
105 _ => true,
106 };
107 }
108 107
109 let init_str = initializer_expr.syntax().text().to_string(); 108 let init_str = initializer_expr.syntax().text().to_string();
110 let init_in_paren = format!("({})", &init_str); 109 let init_in_paren = format!("({})", &init_str);
@@ -116,15 +115,17 @@ pub(crate) fn inline_local_variable(acc: &mut Assists, ctx: &AssistContext) -> O
116 target, 115 target,
117 move |builder| { 116 move |builder| {
118 builder.delete(delete_range); 117 builder.delete(delete_range);
119 for (desc, should_wrap) in refs.iter().zip(wrap_in_parens) { 118 for (reference, should_wrap) in
119 refs.iter().flat_map(|refs| &refs.references).zip(wrap_in_parens)
120 {
120 let replacement = 121 let replacement =
121 if should_wrap { init_in_paren.clone() } else { init_str.clone() }; 122 if should_wrap { init_in_paren.clone() } else { init_str.clone() };
122 match desc.kind { 123 match reference.kind {
123 ReferenceKind::FieldShorthandForLocal => { 124 ReferenceKind::FieldShorthandForLocal => {
124 mark::hit!(inline_field_shorthand); 125 mark::hit!(inline_field_shorthand);
125 builder.insert(desc.file_range.range.end(), format!(": {}", replacement)) 126 builder.insert(reference.range.end(), format!(": {}", replacement))
126 } 127 }
127 _ => builder.replace(desc.file_range.range, replacement), 128 _ => builder.replace(reference.range, replacement),
128 } 129 }
129 } 130 }
130 }, 131 },
diff --git a/crates/assists/src/handlers/remove_unused_param.rs b/crates/assists/src/handlers/remove_unused_param.rs
index 56e8b5229..4f3b8ac46 100644
--- a/crates/assists/src/handlers/remove_unused_param.rs
+++ b/crates/assists/src/handlers/remove_unused_param.rs
@@ -1,8 +1,11 @@
1use ide_db::{defs::Definition, search::Reference}; 1use ide_db::{
2 defs::Definition,
3 search::{FileReference, FileReferences},
4};
2use syntax::{ 5use syntax::{
3 algo::find_node_at_range, 6 algo::find_node_at_range,
4 ast::{self, ArgListOwner}, 7 ast::{self, ArgListOwner},
5 AstNode, SyntaxKind, SyntaxNode, TextRange, T, 8 AstNode, SourceFile, SyntaxKind, SyntaxNode, TextRange, T,
6}; 9};
7use test_utils::mark; 10use test_utils::mark;
8use SyntaxKind::WHITESPACE; 11use SyntaxKind::WHITESPACE;
@@ -58,32 +61,40 @@ pub(crate) fn remove_unused_param(acc: &mut Assists, ctx: &AssistContext) -> Opt
58 param.syntax().text_range(), 61 param.syntax().text_range(),
59 |builder| { 62 |builder| {
60 builder.delete(range_to_remove(param.syntax())); 63 builder.delete(range_to_remove(param.syntax()));
61 for usage in fn_def.usages(&ctx.sema).all() { 64 for usages in fn_def.usages(&ctx.sema).all() {
62 process_usage(ctx, builder, usage, param_position); 65 process_usages(ctx, builder, usages, param_position);
63 } 66 }
64 }, 67 },
65 ) 68 )
66} 69}
67 70
68fn process_usage( 71fn process_usages(
69 ctx: &AssistContext, 72 ctx: &AssistContext,
70 builder: &mut AssistBuilder, 73 builder: &mut AssistBuilder,
71 usage: Reference, 74 usages: FileReferences,
75 arg_to_remove: usize,
76) {
77 let source_file = ctx.sema.parse(usages.file_id);
78 builder.edit_file(usages.file_id);
79 for usage in usages.references {
80 if let Some(text_range) = process_usage(&source_file, usage, arg_to_remove) {
81 builder.delete(text_range);
82 }
83 }
84}
85
86fn process_usage(
87 source_file: &SourceFile,
88 FileReference { range, .. }: FileReference,
72 arg_to_remove: usize, 89 arg_to_remove: usize,
73) -> Option<()> { 90) -> Option<TextRange> {
74 let source_file = ctx.sema.parse(usage.file_range.file_id); 91 let call_expr: ast::CallExpr = find_node_at_range(source_file.syntax(), range)?;
75 let call_expr: ast::CallExpr =
76 find_node_at_range(source_file.syntax(), usage.file_range.range)?;
77 let call_expr_range = call_expr.expr()?.syntax().text_range(); 92 let call_expr_range = call_expr.expr()?.syntax().text_range();
78 if !call_expr_range.contains_range(usage.file_range.range) { 93 if !call_expr_range.contains_range(range) {
79 return None; 94 return None;
80 } 95 }
81 let arg = call_expr.arg_list()?.args().nth(arg_to_remove)?; 96 let arg = call_expr.arg_list()?.args().nth(arg_to_remove)?;
82 97 Some(range_to_remove(arg.syntax()))
83 builder.edit_file(usage.file_range.file_id);
84 builder.delete(range_to_remove(arg.syntax()));
85
86 Some(())
87} 98}
88 99
89fn range_to_remove(node: &SyntaxNode) -> TextRange { 100fn range_to_remove(node: &SyntaxNode) -> TextRange {
diff --git a/crates/ide/src/call_hierarchy.rs b/crates/ide/src/call_hierarchy.rs
index b29d1fef9..90d3b9a31 100644
--- a/crates/ide/src/call_hierarchy.rs
+++ b/crates/ide/src/call_hierarchy.rs
@@ -3,8 +3,8 @@
3use indexmap::IndexMap; 3use indexmap::IndexMap;
4 4
5use hir::Semantics; 5use hir::Semantics;
6use ide_db::call_info::FnCallNode;
7use ide_db::RootDatabase; 6use ide_db::RootDatabase;
7use ide_db::{call_info::FnCallNode, search::FileReferences};
8use syntax::{ast, AstNode, TextRange}; 8use syntax::{ast, AstNode, TextRange};
9 9
10use crate::{ 10use crate::{
@@ -47,22 +47,23 @@ pub(crate) fn incoming_calls(db: &RootDatabase, position: FilePosition) -> Optio
47 47
48 let mut calls = CallLocations::default(); 48 let mut calls = CallLocations::default();
49 49
50 for reference in refs.info.references() { 50 for &FileReferences { file_id, ref references } in refs.info.references() {
51 let file_id = reference.file_range.file_id;
52 let file = sema.parse(file_id); 51 let file = sema.parse(file_id);
53 let file = file.syntax(); 52 let file = file.syntax();
54 let token = file.token_at_offset(reference.file_range.range.start()).next()?; 53 for reference in references {
55 let token = sema.descend_into_macros(token); 54 let token = file.token_at_offset(reference.range.start()).next()?;
56 let syntax = token.parent(); 55 let token = sema.descend_into_macros(token);
57 56 let syntax = token.parent();
58 // This target is the containing function 57
59 if let Some(nav) = syntax.ancestors().find_map(|node| { 58 // This target is the containing function
60 let fn_ = ast::Fn::cast(node)?; 59 if let Some(nav) = syntax.ancestors().find_map(|node| {
61 let def = sema.to_def(&fn_)?; 60 let fn_ = ast::Fn::cast(node)?;
62 def.try_to_nav(sema.db) 61 let def = sema.to_def(&fn_)?;
63 }) { 62 def.try_to_nav(sema.db)
64 let relative_range = reference.file_range.range; 63 }) {
65 calls.add(&nav, relative_range); 64 let relative_range = reference.range;
65 calls.add(&nav, relative_range);
66 }
66 } 67 }
67 } 68 }
68 69
diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs
index 1f368cbd0..1e03832ec 100644
--- a/crates/ide/src/lib.rs
+++ b/crates/ide/src/lib.rs
@@ -92,7 +92,7 @@ pub use ide_db::base_db::{
92}; 92};
93pub use ide_db::{ 93pub use ide_db::{
94 call_info::CallInfo, 94 call_info::CallInfo,
95 search::{Reference, ReferenceAccess, ReferenceKind}, 95 search::{FileReference, ReferenceAccess, ReferenceKind},
96}; 96};
97pub use ide_db::{ 97pub use ide_db::{
98 label::Label, 98 label::Label,
diff --git a/crates/ide/src/references.rs b/crates/ide/src/references.rs
index b774a2be1..132680bfb 100644
--- a/crates/ide/src/references.rs
+++ b/crates/ide/src/references.rs
@@ -14,8 +14,7 @@ pub(crate) mod rename;
14use hir::Semantics; 14use hir::Semantics;
15use ide_db::{ 15use ide_db::{
16 defs::{Definition, NameClass, NameRefClass}, 16 defs::{Definition, NameClass, NameRefClass},
17 search::Reference, 17 search::{FileReference, FileReferences, ReferenceAccess, ReferenceKind, SearchScope},
18 search::{ReferenceAccess, ReferenceKind, SearchScope},
19 RootDatabase, 18 RootDatabase,
20}; 19};
21use syntax::{ 20use syntax::{
@@ -29,7 +28,7 @@ use crate::{display::TryToNav, FilePosition, FileRange, NavigationTarget, RangeI
29#[derive(Debug, Clone)] 28#[derive(Debug, Clone)]
30pub struct ReferenceSearchResult { 29pub struct ReferenceSearchResult {
31 declaration: Declaration, 30 declaration: Declaration,
32 references: Vec<Reference>, 31 references: Vec<FileReferences>,
33} 32}
34 33
35#[derive(Debug, Clone)] 34#[derive(Debug, Clone)]
@@ -48,7 +47,7 @@ impl ReferenceSearchResult {
48 &self.declaration.nav 47 &self.declaration.nav
49 } 48 }
50 49
51 pub fn references(&self) -> &[Reference] { 50 pub fn references(&self) -> &[FileReferences] {
52 &self.references 51 &self.references
53 } 52 }
54 53
@@ -63,20 +62,22 @@ impl ReferenceSearchResult {
63// allow turning ReferenceSearchResult into an iterator 62// allow turning ReferenceSearchResult into an iterator
64// over References 63// over References
65impl IntoIterator for ReferenceSearchResult { 64impl IntoIterator for ReferenceSearchResult {
66 type Item = Reference; 65 type Item = FileReferences;
67 type IntoIter = std::vec::IntoIter<Reference>; 66 type IntoIter = std::vec::IntoIter<FileReferences>;
68 67
69 fn into_iter(mut self) -> Self::IntoIter { 68 fn into_iter(mut self) -> Self::IntoIter {
70 let mut v = Vec::with_capacity(self.len()); 69 let mut v = Vec::with_capacity(self.len());
71 v.push(Reference { 70 v.append(&mut self.references);
72 file_range: FileRange { 71 let decl_ref = FileReference {
73 file_id: self.declaration.nav.file_id, 72 range: self.declaration.nav.focus_or_full_range(),
74 range: self.declaration.nav.focus_or_full_range(),
75 },
76 kind: self.declaration.kind, 73 kind: self.declaration.kind,
77 access: self.declaration.access, 74 access: self.declaration.access,
78 }); 75 };
79 v.append(&mut self.references); 76 let file_id = self.declaration.nav.file_id;
77 match v.iter_mut().find(|it| it.file_id == file_id) {
78 Some(file_refs) => file_refs.references.push(decl_ref),
79 None => v.push(FileReferences { file_id, references: vec![decl_ref] }),
80 }
80 v.into_iter() 81 v.into_iter()
81 } 82 }
82} 83}
@@ -109,13 +110,11 @@ pub(crate) fn find_all_refs(
109 110
110 let RangeInfo { range, info: def } = find_name(&sema, &syntax, position, opt_name)?; 111 let RangeInfo { range, info: def } = find_name(&sema, &syntax, position, opt_name)?;
111 112
112 let references = def 113 let mut references = def.usages(sema).set_scope(search_scope).all();
113 .usages(sema) 114 references.iter_mut().for_each(|it| {
114 .set_scope(search_scope) 115 it.references.retain(|r| search_kind == ReferenceKind::Other || search_kind == r.kind)
115 .all() 116 });
116 .into_iter() 117 references.retain(|r| !r.references.is_empty());
117 .filter(|r| search_kind == ReferenceKind::Other || search_kind == r.kind)
118 .collect();
119 118
120 let nav = def.try_to_nav(sema.db)?; 119 let nav = def.try_to_nav(sema.db)?;
121 let decl_range = nav.focus_or_full_range(); 120 let decl_range = nav.focus_or_full_range();
@@ -255,7 +254,8 @@ fn try_find_self_references(
255 syntax: &SyntaxNode, 254 syntax: &SyntaxNode,
256 position: FilePosition, 255 position: FilePosition,
257) -> Option<RangeInfo<ReferenceSearchResult>> { 256) -> Option<RangeInfo<ReferenceSearchResult>> {
258 let self_token = syntax.token_at_offset(position.offset).find(|t| t.kind() == T![self])?; 257 let FilePosition { file_id, offset } = position;
258 let self_token = syntax.token_at_offset(offset).find(|t| t.kind() == T![self])?;
259 let parent = self_token.parent(); 259 let parent = self_token.parent();
260 match_ast! { 260 match_ast! {
261 match parent { 261 match parent {
@@ -276,7 +276,7 @@ fn try_find_self_references(
276 276
277 let declaration = Declaration { 277 let declaration = Declaration {
278 nav: NavigationTarget { 278 nav: NavigationTarget {
279 file_id: position.file_id, 279 file_id,
280 full_range: self_param.syntax().text_range(), 280 full_range: self_param.syntax().text_range(),
281 focus_range: Some(param_self_token.text_range()), 281 focus_range: Some(param_self_token.text_range()),
282 name: param_self_token.text().clone(), 282 name: param_self_token.text().clone(),
@@ -295,25 +295,29 @@ fn try_find_self_references(
295 let references = function 295 let references = function
296 .body() 296 .body()
297 .map(|body| { 297 .map(|body| {
298 body.syntax() 298 FileReferences {
299 .descendants() 299 file_id,
300 .filter_map(ast::PathExpr::cast) 300 references: body
301 .filter_map(|expr| { 301 .syntax()
302 let path = expr.path()?; 302 .descendants()
303 if path.qualifier().is_none() { 303 .filter_map(ast::PathExpr::cast)
304 path.segment()?.self_token() 304 .filter_map(|expr| {
305 } else { 305 let path = expr.path()?;
306 None 306 if path.qualifier().is_none() {
307 } 307 path.segment()?.self_token()
308 }) 308 } else {
309 .map(|token| Reference { 309 None
310 file_range: FileRange { file_id: position.file_id, range: token.text_range() }, 310 }
311 kind: ReferenceKind::SelfKw, 311 })
312 access: declaration.access, // FIXME: properly check access kind here instead of copying it from the declaration 312 .map(|token| FileReference {
313 }) 313 range: token.text_range(),
314 .collect() 314 kind: ReferenceKind::SelfKw,
315 access: declaration.access, // FIXME: properly check access kind here instead of copying it from the declaration
316 })
317 .collect(),
318 }
315 }) 319 })
316 .unwrap_or_default(); 320 .map_or_else(Vec::default, |it| vec![it]);
317 321
318 Some(RangeInfo::new( 322 Some(RangeInfo::new(
319 param_self_token.text_range(), 323 param_self_token.text_range(),
@@ -324,7 +328,7 @@ fn try_find_self_references(
324#[cfg(test)] 328#[cfg(test)]
325mod tests { 329mod tests {
326 use expect_test::{expect, Expect}; 330 use expect_test::{expect, Expect};
327 use ide_db::base_db::FileId; 331 use ide_db::{base_db::FileId, search::FileReferences};
328 use stdx::format_to; 332 use stdx::format_to;
329 333
330 use crate::{fixture, SearchScope}; 334 use crate::{fixture, SearchScope};
@@ -1018,12 +1022,14 @@ impl Foo {
1018 actual += "\n\n"; 1022 actual += "\n\n";
1019 } 1023 }
1020 1024
1021 for r in &refs.references { 1025 for FileReferences { file_id, references } in refs.references {
1022 format_to!(actual, "{:?} {:?} {:?}", r.file_range.file_id, r.file_range.range, r.kind); 1026 for r in references {
1023 if let Some(access) = r.access { 1027 format_to!(actual, "{:?} {:?} {:?}", file_id, r.range, r.kind);
1024 format_to!(actual, " {:?}", access); 1028 if let Some(access) = r.access {
1029 format_to!(actual, " {:?}", access);
1030 }
1031 actual += "\n";
1025 } 1032 }
1026 actual += "\n";
1027 } 1033 }
1028 expect.assert_eq(&actual) 1034 expect.assert_eq(&actual)
1029 } 1035 }
diff --git a/crates/ide/src/references/rename.rs b/crates/ide/src/references/rename.rs
index 3edc43e08..dd08e1c32 100644
--- a/crates/ide/src/references/rename.rs
+++ b/crates/ide/src/references/rename.rs
@@ -6,9 +6,10 @@ use std::{
6}; 6};
7 7
8use hir::{Module, ModuleDef, ModuleSource, Semantics}; 8use hir::{Module, ModuleDef, ModuleSource, Semantics};
9use ide_db::base_db::{AnchoredPathBuf, FileId, FileRange, SourceDatabaseExt};
10use ide_db::{ 9use ide_db::{
10 base_db::{AnchoredPathBuf, FileId, FileRange, SourceDatabaseExt},
11 defs::{Definition, NameClass, NameRefClass}, 11 defs::{Definition, NameClass, NameRefClass},
12 search::FileReferences,
12 RootDatabase, 13 RootDatabase,
13}; 14};
14use syntax::{ 15use syntax::{
@@ -20,8 +21,8 @@ use test_utils::mark;
20use text_edit::TextEdit; 21use text_edit::TextEdit;
21 22
22use crate::{ 23use crate::{
23 FilePosition, FileSystemEdit, RangeInfo, Reference, ReferenceKind, ReferenceSearchResult, 24 FilePosition, FileSystemEdit, RangeInfo, ReferenceKind, ReferenceSearchResult, SourceChange,
24 SourceChange, SourceFileEdit, TextRange, TextSize, 25 SourceFileEdit, TextRange, TextSize,
25}; 26};
26 27
27type RenameResult<T> = Result<T, RenameError>; 28type RenameResult<T> = Result<T, RenameError>;
@@ -173,39 +174,45 @@ fn find_all_refs(
173 .ok_or_else(|| format_err!("No references found at position")) 174 .ok_or_else(|| format_err!("No references found at position"))
174} 175}
175 176
176fn source_edit_from_reference( 177fn source_edit_from_references(
177 sema: &Semantics<RootDatabase>, 178 sema: &Semantics<RootDatabase>,
178 reference: Reference, 179 &FileReferences { file_id, ref references }: &FileReferences,
179 new_name: &str, 180 new_name: &str,
180) -> SourceFileEdit { 181) -> SourceFileEdit {
181 let mut replacement_text = String::new(); 182 let mut edit = TextEdit::builder();
182 let range = match reference.kind { 183 for reference in references {
183 ReferenceKind::FieldShorthandForField => { 184 let mut replacement_text = String::new();
184 mark::hit!(test_rename_struct_field_for_shorthand); 185 let range = match reference.kind {
185 replacement_text.push_str(new_name); 186 ReferenceKind::FieldShorthandForField => {
186 replacement_text.push_str(": "); 187 mark::hit!(test_rename_struct_field_for_shorthand);
187 TextRange::new(reference.file_range.range.start(), reference.file_range.range.start()) 188 replacement_text.push_str(new_name);
188 } 189 replacement_text.push_str(": ");
189 ReferenceKind::FieldShorthandForLocal => { 190 TextRange::new(reference.range.start(), reference.range.start())
190 mark::hit!(test_rename_local_for_field_shorthand); 191 }
191 replacement_text.push_str(": "); 192 ReferenceKind::FieldShorthandForLocal => {
192 replacement_text.push_str(new_name); 193 mark::hit!(test_rename_local_for_field_shorthand);
193 TextRange::new(reference.file_range.range.end(), reference.file_range.range.end()) 194 replacement_text.push_str(": ");
194 } 195 replacement_text.push_str(new_name);
195 ReferenceKind::RecordFieldExprOrPat => { 196 TextRange::new(reference.range.end(), reference.range.end())
196 mark::hit!(test_rename_field_expr_pat); 197 }
197 replacement_text.push_str(new_name); 198 ReferenceKind::RecordFieldExprOrPat => {
198 edit_text_range_for_record_field_expr_or_pat(sema, reference.file_range, new_name) 199 mark::hit!(test_rename_field_expr_pat);
199 } 200 replacement_text.push_str(new_name);
200 _ => { 201 edit_text_range_for_record_field_expr_or_pat(
201 replacement_text.push_str(new_name); 202 sema,
202 reference.file_range.range 203 FileRange { file_id, range: reference.range },
203 } 204 new_name,
204 }; 205 )
205 SourceFileEdit { 206 }
206 file_id: reference.file_range.file_id, 207 _ => {
207 edit: TextEdit::replace(range, replacement_text), 208 replacement_text.push_str(new_name);
209 reference.range
210 }
211 };
212 edit.replace(range, replacement_text);
208 } 213 }
214
215 SourceFileEdit { file_id, edit: edit.finish() }
209} 216}
210 217
211fn edit_text_range_for_record_field_expr_or_pat( 218fn edit_text_range_for_record_field_expr_or_pat(
@@ -277,9 +284,9 @@ fn rename_mod(
277 284
278 let RangeInfo { range, info: refs } = find_all_refs(sema, position)?; 285 let RangeInfo { range, info: refs } = find_all_refs(sema, position)?;
279 let ref_edits = refs 286 let ref_edits = refs
280 .references 287 .references()
281 .into_iter() 288 .iter()
282 .map(|reference| source_edit_from_reference(sema, reference, new_name)); 289 .map(|reference| source_edit_from_references(sema, reference, new_name));
283 source_file_edits.extend(ref_edits); 290 source_file_edits.extend(ref_edits);
284 291
285 Ok(RangeInfo::new(range, SourceChange::from_edits(source_file_edits, file_system_edits))) 292 Ok(RangeInfo::new(range, SourceChange::from_edits(source_file_edits, file_system_edits)))
@@ -331,17 +338,10 @@ fn rename_to_self(
331 338
332 let RangeInfo { range, info: refs } = find_all_refs(sema, position)?; 339 let RangeInfo { range, info: refs } = find_all_refs(sema, position)?;
333 340
334 let (param_ref, usages): (Vec<Reference>, Vec<Reference>) = refs 341 let mut edits = refs
335 .into_iter() 342 .references()
336 .partition(|reference| param_range.intersect(reference.file_range.range).is_some()); 343 .iter()
337 344 .map(|reference| source_edit_from_references(sema, reference, "self"))
338 if param_ref.is_empty() {
339 bail!("Parameter to rename not found");
340 }
341
342 let mut edits = usages
343 .into_iter()
344 .map(|reference| source_edit_from_reference(sema, reference, "self"))
345 .collect::<Vec<_>>(); 345 .collect::<Vec<_>>();
346 346
347 edits.push(SourceFileEdit { 347 edits.push(SourceFileEdit {
@@ -467,7 +467,7 @@ fn rename_reference(
467 467
468 let edit = refs 468 let edit = refs
469 .into_iter() 469 .into_iter()
470 .map(|reference| source_edit_from_reference(sema, reference, new_name)) 470 .map(|reference| source_edit_from_references(sema, &reference, new_name))
471 .collect::<Vec<_>>(); 471 .collect::<Vec<_>>();
472 472
473 Ok(RangeInfo::new(range, SourceChange::from(edit))) 473 Ok(RangeInfo::new(range, SourceChange::from(edit)))
diff --git a/crates/ide_db/src/search.rs b/crates/ide_db/src/search.rs
index 773bfbc2c..b8359a9b4 100644
--- a/crates/ide_db/src/search.rs
+++ b/crates/ide_db/src/search.rs
@@ -8,6 +8,7 @@ use std::{convert::TryInto, mem};
8 8
9use base_db::{FileId, FileRange, SourceDatabaseExt}; 9use base_db::{FileId, FileRange, SourceDatabaseExt};
10use hir::{DefWithBody, HasSource, Module, ModuleSource, Semantics, Visibility}; 10use hir::{DefWithBody, HasSource, Module, ModuleSource, Semantics, Visibility};
11use itertools::Itertools;
11use once_cell::unsync::Lazy; 12use once_cell::unsync::Lazy;
12use rustc_hash::FxHashMap; 13use rustc_hash::FxHashMap;
13use syntax::{ast, match_ast, AstNode, TextRange, TextSize}; 14use syntax::{ast, match_ast, AstNode, TextRange, TextSize};
@@ -19,8 +20,22 @@ use crate::{
19}; 20};
20 21
21#[derive(Debug, Clone)] 22#[derive(Debug, Clone)]
22pub struct Reference { 23pub struct FileReferences {
23 pub file_range: FileRange, 24 pub file_id: FileId,
25 pub references: Vec<FileReference>,
26}
27
28impl FileReferences {
29 pub fn file_ranges(&self) -> impl Iterator<Item = FileRange> + '_ {
30 self.references
31 .iter()
32 .map(move |&FileReference { range, .. }| FileRange { file_id: self.file_id, range })
33 }
34}
35
36#[derive(Debug, Clone)]
37pub struct FileReference {
38 pub range: TextRange,
24 pub kind: ReferenceKind, 39 pub kind: ReferenceKind,
25 pub access: Option<ReferenceAccess>, 40 pub access: Option<ReferenceAccess>,
26} 41}
@@ -252,23 +267,33 @@ impl<'a> FindUsages<'a> {
252 267
253 pub fn at_least_one(self) -> bool { 268 pub fn at_least_one(self) -> bool {
254 let mut found = false; 269 let mut found = false;
255 self.search(&mut |_reference| { 270 self.search(&mut |_, _| {
256 found = true; 271 found = true;
257 true 272 true
258 }); 273 });
259 found 274 found
260 } 275 }
261 276
262 pub fn all(self) -> Vec<Reference> { 277 /// The [`FileReferences`] returned always have unique [`FileId`]s.
263 let mut res = Vec::new(); 278 pub fn all(self) -> Vec<FileReferences> {
264 self.search(&mut |reference| { 279 let mut res = <Vec<FileReferences>>::new();
265 res.push(reference); 280 self.search(&mut |file_id, reference| {
281 match res.iter_mut().find(|it| it.file_id == file_id) {
282 Some(file_refs) => file_refs.references.push(reference),
283 _ => res.push(FileReferences { file_id, references: vec![reference] }),
284 }
266 false 285 false
267 }); 286 });
287 assert!(res
288 .iter()
289 .map(|refs| refs.file_id)
290 .sorted_unstable()
291 .tuple_windows::<(_, _)>()
292 .all(|(a, b)| a < b));
268 res 293 res
269 } 294 }
270 295
271 fn search(self, sink: &mut dyn FnMut(Reference) -> bool) { 296 fn search(self, sink: &mut dyn FnMut(FileId, FileReference) -> bool) {
272 let _p = profile::span("FindUsages:search"); 297 let _p = profile::span("FindUsages:search");
273 let sema = self.sema; 298 let sema = self.sema;
274 299
@@ -320,16 +345,14 @@ impl<'a> FindUsages<'a> {
320 fn found_lifetime( 345 fn found_lifetime(
321 &self, 346 &self,
322 lifetime: &ast::Lifetime, 347 lifetime: &ast::Lifetime,
323 sink: &mut dyn FnMut(Reference) -> bool, 348 sink: &mut dyn FnMut(FileId, FileReference) -> bool,
324 ) -> bool { 349 ) -> bool {
325 match NameRefClass::classify_lifetime(self.sema, lifetime) { 350 match NameRefClass::classify_lifetime(self.sema, lifetime) {
326 Some(NameRefClass::Definition(def)) if &def == self.def => { 351 Some(NameRefClass::Definition(def)) if &def == self.def => {
327 let reference = Reference { 352 let FileRange { file_id, range } = self.sema.original_range(lifetime.syntax());
328 file_range: self.sema.original_range(lifetime.syntax()), 353 let reference =
329 kind: ReferenceKind::Lifetime, 354 FileReference { range, kind: ReferenceKind::Lifetime, access: None };
330 access: None, 355 sink(file_id, reference)
331 };
332 sink(reference)
333 } 356 }
334 _ => false, // not a usage 357 _ => false, // not a usage
335 } 358 }
@@ -338,7 +361,7 @@ impl<'a> FindUsages<'a> {
338 fn found_name_ref( 361 fn found_name_ref(
339 &self, 362 &self,
340 name_ref: &ast::NameRef, 363 name_ref: &ast::NameRef,
341 sink: &mut dyn FnMut(Reference) -> bool, 364 sink: &mut dyn FnMut(FileId, FileReference) -> bool,
342 ) -> bool { 365 ) -> bool {
343 match NameRefClass::classify(self.sema, &name_ref) { 366 match NameRefClass::classify(self.sema, &name_ref) {
344 Some(NameRefClass::Definition(def)) if &def == self.def => { 367 Some(NameRefClass::Definition(def)) if &def == self.def => {
@@ -352,46 +375,50 @@ impl<'a> FindUsages<'a> {
352 ReferenceKind::Other 375 ReferenceKind::Other
353 }; 376 };
354 377
355 let reference = Reference { 378 let FileRange { file_id, range } = self.sema.original_range(name_ref.syntax());
356 file_range: self.sema.original_range(name_ref.syntax()), 379 let reference =
357 kind, 380 FileReference { range, kind, access: reference_access(&def, &name_ref) };
358 access: reference_access(&def, &name_ref), 381 sink(file_id, reference)
359 };
360 sink(reference)
361 } 382 }
362 Some(NameRefClass::FieldShorthand { local_ref: local, field_ref: field }) => { 383 Some(NameRefClass::FieldShorthand { local_ref: local, field_ref: field }) => {
384 let FileRange { file_id, range } = self.sema.original_range(name_ref.syntax());
363 let reference = match self.def { 385 let reference = match self.def {
364 Definition::Field(_) if &field == self.def => Reference { 386 Definition::Field(_) if &field == self.def => FileReference {
365 file_range: self.sema.original_range(name_ref.syntax()), 387 range,
366 kind: ReferenceKind::FieldShorthandForField, 388 kind: ReferenceKind::FieldShorthandForField,
367 access: reference_access(&field, &name_ref), 389 access: reference_access(&field, &name_ref),
368 }, 390 },
369 Definition::Local(l) if &local == l => Reference { 391 Definition::Local(l) if &local == l => FileReference {
370 file_range: self.sema.original_range(name_ref.syntax()), 392 range,
371 kind: ReferenceKind::FieldShorthandForLocal, 393 kind: ReferenceKind::FieldShorthandForLocal,
372 access: reference_access(&Definition::Local(local), &name_ref), 394 access: reference_access(&Definition::Local(local), &name_ref),
373 }, 395 },
374 _ => return false, // not a usage 396 _ => return false, // not a usage
375 }; 397 };
376 sink(reference) 398 sink(file_id, reference)
377 } 399 }
378 _ => false, // not a usage 400 _ => false, // not a usage
379 } 401 }
380 } 402 }
381 403
382 fn found_name(&self, name: &ast::Name, sink: &mut dyn FnMut(Reference) -> bool) -> bool { 404 fn found_name(
405 &self,
406 name: &ast::Name,
407 sink: &mut dyn FnMut(FileId, FileReference) -> bool,
408 ) -> bool {
383 match NameClass::classify(self.sema, name) { 409 match NameClass::classify(self.sema, name) {
384 Some(NameClass::PatFieldShorthand { local_def: _, field_ref }) => { 410 Some(NameClass::PatFieldShorthand { local_def: _, field_ref }) => {
385 let reference = match self.def { 411 if !matches!(self.def, Definition::Field(_) if &field_ref == self.def) {
386 Definition::Field(_) if &field_ref == self.def => Reference { 412 return false;
387 file_range: self.sema.original_range(name.syntax()), 413 }
388 kind: ReferenceKind::FieldShorthandForField, 414 let FileRange { file_id, range } = self.sema.original_range(name.syntax());
389 // FIXME: mutable patterns should have `Write` access 415 let reference = FileReference {
390 access: Some(ReferenceAccess::Read), 416 range,
391 }, 417 kind: ReferenceKind::FieldShorthandForField,
392 _ => return false, // not a usage 418 // FIXME: mutable patterns should have `Write` access
419 access: Some(ReferenceAccess::Read),
393 }; 420 };
394 sink(reference) 421 sink(file_id, reference)
395 } 422 }
396 _ => false, // not a usage 423 _ => false, // not a usage
397 } 424 }
diff --git a/crates/rust-analyzer/src/handlers.rs b/crates/rust-analyzer/src/handlers.rs
index 29cc9051e..d862f370a 100644
--- a/crates/rust-analyzer/src/handlers.rs
+++ b/crates/rust-analyzer/src/handlers.rs
@@ -12,6 +12,7 @@ use ide::{
12 FileId, FilePosition, FileRange, HoverAction, HoverGotoTypeData, LineIndex, NavigationTarget, 12 FileId, FilePosition, FileRange, HoverAction, HoverGotoTypeData, LineIndex, NavigationTarget,
13 Query, RangeInfo, Runnable, RunnableKind, SearchScope, SourceChange, SymbolKind, TextEdit, 13 Query, RangeInfo, Runnable, RunnableKind, SearchScope, SourceChange, SymbolKind, TextEdit,
14}; 14};
15use ide_db::search::FileReferences;
15use itertools::Itertools; 16use itertools::Itertools;
16use lsp_server::ErrorCode; 17use lsp_server::ErrorCode;
17use lsp_types::{ 18use lsp_types::{
@@ -812,14 +813,19 @@ pub(crate) fn handle_references(
812 }; 813 };
813 814
814 let locations = if params.context.include_declaration { 815 let locations = if params.context.include_declaration {
815 refs.into_iter() 816 let mut locations = Vec::default();
816 .filter_map(|reference| to_proto::location(&snap, reference.file_range).ok()) 817 refs.into_iter().for_each(|it| {
817 .collect() 818 locations.extend(
819 it.file_ranges().filter_map(|frange| to_proto::location(&snap, frange).ok()),
820 )
821 });
822 locations
818 } else { 823 } else {
819 // Only iterate over the references if include_declaration was false 824 // Only iterate over the references if include_declaration was false
820 refs.references() 825 refs.references()
821 .iter() 826 .iter()
822 .filter_map(|reference| to_proto::location(&snap, reference.file_range).ok()) 827 .flat_map(FileReferences::file_ranges)
828 .filter_map(|frange| to_proto::location(&snap, frange).ok())
823 .collect() 829 .collect()
824 }; 830 };
825 831
@@ -1176,7 +1182,8 @@ pub(crate) fn handle_code_lens_resolve(
1176 .map(|r| { 1182 .map(|r| {
1177 r.references() 1183 r.references()
1178 .iter() 1184 .iter()
1179 .filter_map(|it| to_proto::location(&snap, it.file_range).ok()) 1185 .flat_map(FileReferences::file_ranges)
1186 .filter_map(|frange| to_proto::location(&snap, frange).ok())
1180 .collect_vec() 1187 .collect_vec()
1181 }) 1188 })
1182 .unwrap_or_default(); 1189 .unwrap_or_default();
@@ -1221,12 +1228,18 @@ pub(crate) fn handle_document_highlight(
1221 1228
1222 let res = refs 1229 let res = refs
1223 .into_iter() 1230 .into_iter()
1224 .filter(|reference| reference.file_range.file_id == position.file_id) 1231 .find(|refs| refs.file_id == position.file_id)
1225 .map(|reference| DocumentHighlight { 1232 .map(|file_refs| {
1226 range: to_proto::range(&line_index, reference.file_range.range), 1233 file_refs
1227 kind: reference.access.map(to_proto::document_highlight_kind), 1234 .references
1235 .into_iter()
1236 .map(|r| DocumentHighlight {
1237 range: to_proto::range(&line_index, r.range),
1238 kind: r.access.map(to_proto::document_highlight_kind),
1239 })
1240 .collect()
1228 }) 1241 })
1229 .collect(); 1242 .unwrap_or_default();
1230 Ok(Some(res)) 1243 Ok(Some(res))
1231} 1244}
1232 1245
diff --git a/crates/ssr/src/search.rs b/crates/ssr/src/search.rs
index 44b5db029..a1d653aff 100644
--- a/crates/ssr/src/search.rs
+++ b/crates/ssr/src/search.rs
@@ -5,10 +5,10 @@ use crate::{
5 resolving::{ResolvedPath, ResolvedPattern, ResolvedRule}, 5 resolving::{ResolvedPath, ResolvedPattern, ResolvedRule},
6 Match, MatchFinder, 6 Match, MatchFinder,
7}; 7};
8use ide_db::base_db::{FileId, FileRange};
9use ide_db::{ 8use ide_db::{
9 base_db::{FileId, FileRange},
10 defs::Definition, 10 defs::Definition,
11 search::{Reference, SearchScope}, 11 search::{FileReferences, SearchScope},
12}; 12};
13use rustc_hash::FxHashSet; 13use rustc_hash::FxHashSet;
14use syntax::{ast, AstNode, SyntaxKind, SyntaxNode}; 14use syntax::{ast, AstNode, SyntaxKind, SyntaxNode};
@@ -20,7 +20,7 @@ use test_utils::mark;
20/// them more than once. 20/// them more than once.
21#[derive(Default)] 21#[derive(Default)]
22pub(crate) struct UsageCache { 22pub(crate) struct UsageCache {
23 usages: Vec<(Definition, Vec<Reference>)>, 23 usages: Vec<(Definition, Vec<FileReferences>)>,
24} 24}
25 25
26impl<'db> MatchFinder<'db> { 26impl<'db> MatchFinder<'db> {
@@ -58,8 +58,12 @@ impl<'db> MatchFinder<'db> {
58 ) { 58 ) {
59 if let Some(resolved_path) = pick_path_for_usages(pattern) { 59 if let Some(resolved_path) = pick_path_for_usages(pattern) {
60 let definition: Definition = resolved_path.resolution.clone().into(); 60 let definition: Definition = resolved_path.resolution.clone().into();
61 for reference in self.find_usages(usage_cache, definition) { 61 for file_range in self
62 if let Some(node_to_match) = self.find_node_to_match(resolved_path, reference) { 62 .find_usages(usage_cache, definition)
63 .iter()
64 .flat_map(FileReferences::file_ranges)
65 {
66 if let Some(node_to_match) = self.find_node_to_match(resolved_path, file_range) {
63 if !is_search_permitted_ancestors(&node_to_match) { 67 if !is_search_permitted_ancestors(&node_to_match) {
64 mark::hit!(use_declaration_with_braces); 68 mark::hit!(use_declaration_with_braces);
65 continue; 69 continue;
@@ -73,11 +77,11 @@ impl<'db> MatchFinder<'db> {
73 fn find_node_to_match( 77 fn find_node_to_match(
74 &self, 78 &self,
75 resolved_path: &ResolvedPath, 79 resolved_path: &ResolvedPath,
76 reference: &Reference, 80 file_range: FileRange,
77 ) -> Option<SyntaxNode> { 81 ) -> Option<SyntaxNode> {
78 let file = self.sema.parse(reference.file_range.file_id); 82 let file = self.sema.parse(file_range.file_id);
79 let depth = resolved_path.depth as usize; 83 let depth = resolved_path.depth as usize;
80 let offset = reference.file_range.range.start(); 84 let offset = file_range.range.start();
81 if let Some(path) = 85 if let Some(path) =
82 self.sema.find_node_at_offset_with_descend::<ast::Path>(file.syntax(), offset) 86 self.sema.find_node_at_offset_with_descend::<ast::Path>(file.syntax(), offset)
83 { 87 {
@@ -108,7 +112,7 @@ impl<'db> MatchFinder<'db> {
108 &self, 112 &self,
109 usage_cache: &'a mut UsageCache, 113 usage_cache: &'a mut UsageCache,
110 definition: Definition, 114 definition: Definition,
111 ) -> &'a [Reference] { 115 ) -> &'a [FileReferences] {
112 // Logically if a lookup succeeds we should just return it. Unfortunately returning it would 116 // Logically if a lookup succeeds we should just return it. Unfortunately returning it would
113 // extend the lifetime of the borrow, then we wouldn't be able to do the insertion on a 117 // extend the lifetime of the borrow, then we wouldn't be able to do the insertion on a
114 // cache miss. This is a limitation of NLL and is fixed with Polonius. For now we do two 118 // cache miss. This is a limitation of NLL and is fixed with Polonius. For now we do two
@@ -250,7 +254,7 @@ fn is_search_permitted(node: &SyntaxNode) -> bool {
250} 254}
251 255
252impl UsageCache { 256impl UsageCache {
253 fn find(&mut self, definition: &Definition) -> Option<&[Reference]> { 257 fn find(&mut self, definition: &Definition) -> Option<&[FileReferences]> {
254 // We expect a very small number of cache entries (generally 1), so a linear scan should be 258 // We expect a very small number of cache entries (generally 1), so a linear scan should be
255 // fast enough and avoids the need to implement Hash for Definition. 259 // fast enough and avoids the need to implement Hash for Definition.
256 for (d, refs) in &self.usages { 260 for (d, refs) in &self.usages {