diff options
Diffstat (limited to 'crates')
-rw-r--r-- | crates/assists/src/handlers/extract_struct_from_enum_variant.rs | 59 | ||||
-rw-r--r-- | crates/assists/src/handlers/inline_local_variable.rs | 95 | ||||
-rw-r--r-- | crates/assists/src/handlers/remove_unused_param.rs | 43 | ||||
-rw-r--r-- | crates/ide/src/call_hierarchy.rs | 31 | ||||
-rw-r--r-- | crates/ide/src/lib.rs | 2 | ||||
-rw-r--r-- | crates/ide/src/references.rs | 98 | ||||
-rw-r--r-- | crates/ide/src/references/rename.rs | 94 | ||||
-rw-r--r-- | crates/ide_db/src/search.rs | 101 | ||||
-rw-r--r-- | crates/rust-analyzer/src/handlers.rs | 33 | ||||
-rw-r--r-- | crates/ssr/src/search.rs | 24 |
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 | ||
3 | use either::Either; | 3 | use either::Either; |
4 | use hir::{AsName, Module, ModuleDef, Name, Variant}; | 4 | use hir::{AsName, Module, ModuleDef, Name, Variant}; |
5 | use ide_db::helpers::{ | 5 | use 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 | }; |
9 | use ide_db::{defs::Definition, search::Reference, RootDatabase}; | 14 | use rustc_hash::FxHashSet; |
10 | use rustc_hash::{FxHashMap, FxHashSet}; | ||
11 | use syntax::{ | 15 | use 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 | |||
205 | fn update_reference( | 210 | fn 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 @@ | |||
1 | use ide_db::{defs::Definition, search::ReferenceKind}; | 1 | use ide_db::{ |
2 | defs::Definition, | ||
3 | search::{FileReference, ReferenceKind}, | ||
4 | }; | ||
2 | use syntax::{ | 5 | use 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 @@ | |||
1 | use ide_db::{defs::Definition, search::Reference}; | 1 | use ide_db::{ |
2 | defs::Definition, | ||
3 | search::{FileReference, FileReferences}, | ||
4 | }; | ||
2 | use syntax::{ | 5 | use 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 | }; |
7 | use test_utils::mark; | 10 | use test_utils::mark; |
8 | use SyntaxKind::WHITESPACE; | 11 | use 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 | ||
68 | fn process_usage( | 71 | fn 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 | |||
86 | fn 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 | ||
89 | fn range_to_remove(node: &SyntaxNode) -> TextRange { | 100 | fn 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 @@ | |||
3 | use indexmap::IndexMap; | 3 | use indexmap::IndexMap; |
4 | 4 | ||
5 | use hir::Semantics; | 5 | use hir::Semantics; |
6 | use ide_db::call_info::FnCallNode; | ||
7 | use ide_db::RootDatabase; | 6 | use ide_db::RootDatabase; |
7 | use ide_db::{call_info::FnCallNode, search::FileReferences}; | ||
8 | use syntax::{ast, AstNode, TextRange}; | 8 | use syntax::{ast, AstNode, TextRange}; |
9 | 9 | ||
10 | use crate::{ | 10 | use 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 | }; |
93 | pub use ide_db::{ | 93 | pub use ide_db::{ |
94 | call_info::CallInfo, | 94 | call_info::CallInfo, |
95 | search::{Reference, ReferenceAccess, ReferenceKind}, | 95 | search::{FileReference, ReferenceAccess, ReferenceKind}, |
96 | }; | 96 | }; |
97 | pub use ide_db::{ | 97 | pub 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; | |||
14 | use hir::Semantics; | 14 | use hir::Semantics; |
15 | use ide_db::{ | 15 | use 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 | }; |
21 | use syntax::{ | 20 | use syntax::{ |
@@ -29,7 +28,7 @@ use crate::{display::TryToNav, FilePosition, FileRange, NavigationTarget, RangeI | |||
29 | #[derive(Debug, Clone)] | 28 | #[derive(Debug, Clone)] |
30 | pub struct ReferenceSearchResult { | 29 | pub 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 |
65 | impl IntoIterator for ReferenceSearchResult { | 64 | impl 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)] |
325 | mod tests { | 329 | mod 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 | ||
8 | use hir::{Module, ModuleDef, ModuleSource, Semantics}; | 8 | use hir::{Module, ModuleDef, ModuleSource, Semantics}; |
9 | use ide_db::base_db::{AnchoredPathBuf, FileId, FileRange, SourceDatabaseExt}; | ||
10 | use ide_db::{ | 9 | use 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 | }; |
14 | use syntax::{ | 15 | use syntax::{ |
@@ -20,8 +21,8 @@ use test_utils::mark; | |||
20 | use text_edit::TextEdit; | 21 | use text_edit::TextEdit; |
21 | 22 | ||
22 | use crate::{ | 23 | use 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 | ||
27 | type RenameResult<T> = Result<T, RenameError>; | 28 | type 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 | ||
176 | fn source_edit_from_reference( | 177 | fn 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 | ||
211 | fn edit_text_range_for_record_field_expr_or_pat( | 218 | fn 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 | ||
9 | use base_db::{FileId, FileRange, SourceDatabaseExt}; | 9 | use base_db::{FileId, FileRange, SourceDatabaseExt}; |
10 | use hir::{DefWithBody, HasSource, Module, ModuleSource, Semantics, Visibility}; | 10 | use hir::{DefWithBody, HasSource, Module, ModuleSource, Semantics, Visibility}; |
11 | use itertools::Itertools; | ||
11 | use once_cell::unsync::Lazy; | 12 | use once_cell::unsync::Lazy; |
12 | use rustc_hash::FxHashMap; | 13 | use rustc_hash::FxHashMap; |
13 | use syntax::{ast, match_ast, AstNode, TextRange, TextSize}; | 14 | use 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)] |
22 | pub struct Reference { | 23 | pub struct FileReferences { |
23 | pub file_range: FileRange, | 24 | pub file_id: FileId, |
25 | pub references: Vec<FileReference>, | ||
26 | } | ||
27 | |||
28 | impl 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)] | ||
37 | pub 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 | }; |
15 | use ide_db::search::FileReferences; | ||
15 | use itertools::Itertools; | 16 | use itertools::Itertools; |
16 | use lsp_server::ErrorCode; | 17 | use lsp_server::ErrorCode; |
17 | use lsp_types::{ | 18 | use 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 | }; |
8 | use ide_db::base_db::{FileId, FileRange}; | ||
9 | use ide_db::{ | 8 | use ide_db::{ |
9 | base_db::{FileId, FileRange}, | ||
10 | defs::Definition, | 10 | defs::Definition, |
11 | search::{Reference, SearchScope}, | 11 | search::{FileReferences, SearchScope}, |
12 | }; | 12 | }; |
13 | use rustc_hash::FxHashSet; | 13 | use rustc_hash::FxHashSet; |
14 | use syntax::{ast, AstNode, SyntaxKind, SyntaxNode}; | 14 | use 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)] |
22 | pub(crate) struct UsageCache { | 22 | pub(crate) struct UsageCache { |
23 | usages: Vec<(Definition, Vec<Reference>)>, | 23 | usages: Vec<(Definition, Vec<FileReferences>)>, |
24 | } | 24 | } |
25 | 25 | ||
26 | impl<'db> MatchFinder<'db> { | 26 | impl<'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 | ||
252 | impl UsageCache { | 256 | impl 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 { |