aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/ra_assists/src/handlers/inline_local_variable.rs29
-rw-r--r--crates/ra_assists/src/marks.rs5
-rw-r--r--crates/ra_hir/src/semantics.rs8
-rw-r--r--crates/ra_hir/src/source_analyzer.rs35
4 files changed, 23 insertions, 54 deletions
diff --git a/crates/ra_assists/src/handlers/inline_local_variable.rs b/crates/ra_assists/src/handlers/inline_local_variable.rs
index eb5112343..3bfcba8ff 100644
--- a/crates/ra_assists/src/handlers/inline_local_variable.rs
+++ b/crates/ra_assists/src/handlers/inline_local_variable.rs
@@ -1,3 +1,4 @@
1use ra_ide_db::defs::Definition;
1use ra_syntax::{ 2use ra_syntax::{
2 ast::{self, AstNode, AstToken}, 3 ast::{self, AstNode, AstToken},
3 TextRange, 4 TextRange,
@@ -37,6 +38,15 @@ pub(crate) fn inline_local_variable(ctx: AssistCtx) -> Option<Assist> {
37 return None; 38 return None;
38 } 39 }
39 let initializer_expr = let_stmt.initializer()?; 40 let initializer_expr = let_stmt.initializer()?;
41
42 let def = ctx.sema.to_def(&bind_pat)?;
43 let def = Definition::Local(def);
44 let refs = def.find_usages(ctx.db, None);
45 if refs.is_empty() {
46 tested_by!(test_not_applicable_if_variable_unused);
47 return None;
48 };
49
40 let delete_range = if let Some(whitespace) = let_stmt 50 let delete_range = if let Some(whitespace) = let_stmt
41 .syntax() 51 .syntax()
42 .next_sibling_or_token() 52 .next_sibling_or_token()
@@ -49,16 +59,14 @@ pub(crate) fn inline_local_variable(ctx: AssistCtx) -> Option<Assist> {
49 } else { 59 } else {
50 let_stmt.syntax().text_range() 60 let_stmt.syntax().text_range()
51 }; 61 };
52 let refs = ctx.sema.find_all_refs(&bind_pat);
53 if refs.is_empty() {
54 return None;
55 };
56 62
57 let mut wrap_in_parens = vec![true; refs.len()]; 63 let mut wrap_in_parens = vec![true; refs.len()];
58 64
59 for (i, desc) in refs.iter().enumerate() { 65 for (i, desc) in refs.iter().enumerate() {
60 let usage_node = 66 let usage_node = ctx
61 ctx.covering_node_for_range(desc.range).ancestors().find_map(ast::PathExpr::cast)?; 67 .covering_node_for_range(desc.file_range.range)
68 .ancestors()
69 .find_map(ast::PathExpr::cast)?;
62 let usage_parent_option = usage_node.syntax().parent().and_then(ast::Expr::cast); 70 let usage_parent_option = usage_node.syntax().parent().and_then(ast::Expr::cast);
63 let usage_parent = match usage_parent_option { 71 let usage_parent = match usage_parent_option {
64 Some(u) => u, 72 Some(u) => u,
@@ -103,11 +111,9 @@ pub(crate) fn inline_local_variable(ctx: AssistCtx) -> Option<Assist> {
103 move |edit: &mut ActionBuilder| { 111 move |edit: &mut ActionBuilder| {
104 edit.delete(delete_range); 112 edit.delete(delete_range);
105 for (desc, should_wrap) in refs.iter().zip(wrap_in_parens) { 113 for (desc, should_wrap) in refs.iter().zip(wrap_in_parens) {
106 if should_wrap { 114 let replacement =
107 edit.replace(desc.range, init_in_paren.clone()) 115 if should_wrap { init_in_paren.clone() } else { init_str.clone() };
108 } else { 116 edit.replace(desc.file_range.range, replacement)
109 edit.replace(desc.range, init_str.clone())
110 }
111 } 117 }
112 edit.set_cursor(delete_range.start()) 118 edit.set_cursor(delete_range.start())
113 }, 119 },
@@ -657,6 +663,7 @@ fn foo() {
657 663
658 #[test] 664 #[test]
659 fn test_not_applicable_if_variable_unused() { 665 fn test_not_applicable_if_variable_unused() {
666 covers!(test_not_applicable_if_variable_unused);
660 check_assist_not_applicable( 667 check_assist_not_applicable(
661 inline_local_variable, 668 inline_local_variable,
662 r" 669 r"
diff --git a/crates/ra_assists/src/marks.rs b/crates/ra_assists/src/marks.rs
index cef3df4e5..22404ee80 100644
--- a/crates/ra_assists/src/marks.rs
+++ b/crates/ra_assists/src/marks.rs
@@ -1,9 +1,10 @@
1//! See test_utils/src/marks.rs 1//! See test_utils/src/marks.rs
2 2
3test_utils::marks!( 3test_utils::marks![
4 introduce_var_in_comment_is_not_applicable 4 introduce_var_in_comment_is_not_applicable
5 test_introduce_var_expr_stmt 5 test_introduce_var_expr_stmt
6 test_introduce_var_last_expr 6 test_introduce_var_last_expr
7 not_applicable_outside_of_bind_pat 7 not_applicable_outside_of_bind_pat
8 test_not_inline_mut_variable 8 test_not_inline_mut_variable
9); 9 test_not_applicable_if_variable_unused
10];
diff --git a/crates/ra_hir/src/semantics.rs b/crates/ra_hir/src/semantics.rs
index afc7f7ee7..7ce785791 100644
--- a/crates/ra_hir/src/semantics.rs
+++ b/crates/ra_hir/src/semantics.rs
@@ -19,7 +19,7 @@ use rustc_hash::{FxHashMap, FxHashSet};
19use crate::{ 19use crate::{
20 db::HirDatabase, 20 db::HirDatabase,
21 semantics::source_to_def::{ChildContainer, SourceToDefCache, SourceToDefCtx}, 21 semantics::source_to_def::{ChildContainer, SourceToDefCache, SourceToDefCtx},
22 source_analyzer::{resolve_hir_path, ReferenceDescriptor, SourceAnalyzer}, 22 source_analyzer::{resolve_hir_path, SourceAnalyzer},
23 Function, HirFileId, InFile, Local, MacroDef, Module, ModuleDef, Name, Origin, Path, 23 Function, HirFileId, InFile, Local, MacroDef, Module, ModuleDef, Name, Origin, Path,
24 PathResolution, ScopeDef, StructField, Trait, Type, TypeParam, VariantDef, 24 PathResolution, ScopeDef, StructField, Trait, Type, TypeParam, VariantDef,
25}; 25};
@@ -171,12 +171,6 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
171 SemanticsScope { db: self.db, resolver } 171 SemanticsScope { db: self.db, resolver }
172 } 172 }
173 173
174 // FIXME: we only use this in `inline_local_variable` assist, ideally, we
175 // should switch to general reference search infra there.
176 pub fn find_all_refs(&self, pat: &ast::BindPat) -> Vec<ReferenceDescriptor> {
177 self.analyze(pat.syntax()).find_all_refs(pat)
178 }
179
180 fn analyze(&self, node: &SyntaxNode) -> SourceAnalyzer { 174 fn analyze(&self, node: &SyntaxNode) -> SourceAnalyzer {
181 let src = self.find_file(node.clone()); 175 let src = self.find_file(node.clone());
182 self.analyze2(src.as_ref(), None) 176 self.analyze2(src.as_ref(), None)
diff --git a/crates/ra_hir/src/source_analyzer.rs b/crates/ra_hir/src/source_analyzer.rs
index 015389fb0..73cff17c9 100644
--- a/crates/ra_hir/src/source_analyzer.rs
+++ b/crates/ra_hir/src/source_analyzer.rs
@@ -7,7 +7,6 @@
7//! purely for "IDE needs". 7//! purely for "IDE needs".
8use std::{iter::once, sync::Arc}; 8use std::{iter::once, sync::Arc};
9 9
10use either::Either;
11use hir_def::{ 10use hir_def::{
12 body::{ 11 body::{
13 scope::{ExprScopes, ScopeId}, 12 scope::{ExprScopes, ScopeId},
@@ -21,7 +20,7 @@ use hir_expand::{hygiene::Hygiene, name::AsName, HirFileId, InFile};
21use hir_ty::{InEnvironment, InferenceResult, TraitEnvironment}; 20use hir_ty::{InEnvironment, InferenceResult, TraitEnvironment};
22use ra_syntax::{ 21use ra_syntax::{
23 ast::{self, AstNode}, 22 ast::{self, AstNode},
24 AstPtr, SyntaxNode, SyntaxNodePtr, TextRange, TextUnit, 23 SyntaxNode, SyntaxNodePtr, TextRange, TextUnit,
25}; 24};
26 25
27use crate::{ 26use crate::{
@@ -251,38 +250,6 @@ impl SourceAnalyzer {
251 resolve_hir_path(db, &self.resolver, &hir_path) 250 resolve_hir_path(db, &self.resolver, &hir_path)
252 } 251 }
253 252
254 fn resolve_local_name(
255 &self,
256 name_ref: &ast::NameRef,
257 ) -> Option<Either<AstPtr<ast::Pat>, AstPtr<ast::SelfParam>>> {
258 let name = name_ref.as_name();
259 let source_map = self.body_source_map.as_ref()?;
260 let scopes = self.scopes.as_ref()?;
261 let scope = scope_for(scopes, source_map, InFile::new(self.file_id, name_ref.syntax()))?;
262 let entry = scopes.resolve_name_in_scope(scope, &name)?;
263 Some(source_map.pat_syntax(entry.pat())?.value)
264 }
265
266 // FIXME: we only use this in `inline_local_variable` assist, ideally, we
267 // should switch to general reference search infra there.
268 pub(crate) fn find_all_refs(&self, pat: &ast::BindPat) -> Vec<ReferenceDescriptor> {
269 let fn_def = pat.syntax().ancestors().find_map(ast::FnDef::cast).unwrap();
270 let ptr = Either::Left(AstPtr::new(&ast::Pat::from(pat.clone())));
271 fn_def
272 .syntax()
273 .descendants()
274 .filter_map(ast::NameRef::cast)
275 .filter(|name_ref| match self.resolve_local_name(&name_ref) {
276 None => false,
277 Some(d_ptr) => d_ptr == ptr,
278 })
279 .map(|name_ref| ReferenceDescriptor {
280 name: name_ref.text().to_string(),
281 range: name_ref.syntax().text_range(),
282 })
283 .collect()
284 }
285
286 pub(crate) fn expand( 253 pub(crate) fn expand(
287 &self, 254 &self,
288 db: &impl HirDatabase, 255 db: &impl HirDatabase,