diff options
Diffstat (limited to 'crates/ra_assists/src')
-rw-r--r-- | crates/ra_assists/src/assist_ctx.rs | 10 | ||||
-rw-r--r-- | crates/ra_assists/src/assists/add_explicit_type.rs | 2 | ||||
-rw-r--r-- | crates/ra_assists/src/assists/add_missing_impl_members.rs | 3 | ||||
-rw-r--r-- | crates/ra_assists/src/assists/add_new.rs | 69 | ||||
-rw-r--r-- | crates/ra_assists/src/assists/fill_match_arms.rs | 3 | ||||
-rw-r--r-- | crates/ra_assists/src/assists/inline_local_variable.rs | 2 | ||||
-rw-r--r-- | crates/ra_assists/src/assists/raw_string.rs | 59 |
7 files changed, 89 insertions, 59 deletions
diff --git a/crates/ra_assists/src/assist_ctx.rs b/crates/ra_assists/src/assist_ctx.rs index 1908bdec9..0ea84d548 100644 --- a/crates/ra_assists/src/assist_ctx.rs +++ b/crates/ra_assists/src/assist_ctx.rs | |||
@@ -1,6 +1,5 @@ | |||
1 | //! This module defines `AssistCtx` -- the API surface that is exposed to assists. | 1 | //! This module defines `AssistCtx` -- the API surface that is exposed to assists. |
2 | 2 | use hir::{db::HirDatabase, SourceAnalyzer}; | |
3 | use hir::db::HirDatabase; | ||
4 | use ra_db::FileRange; | 3 | use ra_db::FileRange; |
5 | use ra_fmt::{leading_indent, reindent}; | 4 | use ra_fmt::{leading_indent, reindent}; |
6 | use ra_syntax::{ | 5 | use ra_syntax::{ |
@@ -113,6 +112,13 @@ impl<'a, DB: HirDatabase> AssistCtx<'a, DB> { | |||
113 | pub(crate) fn covering_element(&self) -> SyntaxElement { | 112 | pub(crate) fn covering_element(&self) -> SyntaxElement { |
114 | find_covering_element(self.source_file.syntax(), self.frange.range) | 113 | find_covering_element(self.source_file.syntax(), self.frange.range) |
115 | } | 114 | } |
115 | pub(crate) fn source_analyzer( | ||
116 | &self, | ||
117 | node: &SyntaxNode, | ||
118 | offset: Option<TextUnit>, | ||
119 | ) -> SourceAnalyzer { | ||
120 | SourceAnalyzer::new(self.db, hir::Source::new(self.frange.file_id.into(), node), offset) | ||
121 | } | ||
116 | 122 | ||
117 | pub(crate) fn covering_node_for_range(&self, range: TextRange) -> SyntaxElement { | 123 | pub(crate) fn covering_node_for_range(&self, range: TextRange) -> SyntaxElement { |
118 | find_covering_element(self.source_file.syntax(), range) | 124 | find_covering_element(self.source_file.syntax(), range) |
diff --git a/crates/ra_assists/src/assists/add_explicit_type.rs b/crates/ra_assists/src/assists/add_explicit_type.rs index ddda1a0f2..562a09685 100644 --- a/crates/ra_assists/src/assists/add_explicit_type.rs +++ b/crates/ra_assists/src/assists/add_explicit_type.rs | |||
@@ -40,7 +40,7 @@ pub(crate) fn add_explicit_type(ctx: AssistCtx<impl HirDatabase>) -> Option<Assi | |||
40 | } | 40 | } |
41 | // Infer type | 41 | // Infer type |
42 | let db = ctx.db; | 42 | let db = ctx.db; |
43 | let analyzer = hir::SourceAnalyzer::new(db, ctx.frange.file_id, stmt.syntax(), None); | 43 | let analyzer = ctx.source_analyzer(stmt.syntax(), None); |
44 | let ty = analyzer.type_of(db, &expr)?; | 44 | let ty = analyzer.type_of(db, &expr)?; |
45 | // Assist not applicable if the type is unknown | 45 | // Assist not applicable if the type is unknown |
46 | if is_unknown(&ty) { | 46 | if is_unknown(&ty) { |
diff --git a/crates/ra_assists/src/assists/add_missing_impl_members.rs b/crates/ra_assists/src/assists/add_missing_impl_members.rs index 41de23921..91af161ee 100644 --- a/crates/ra_assists/src/assists/add_missing_impl_members.rs +++ b/crates/ra_assists/src/assists/add_missing_impl_members.rs | |||
@@ -100,8 +100,7 @@ fn add_missing_impl_members_inner( | |||
100 | let impl_item_list = impl_node.item_list()?; | 100 | let impl_item_list = impl_node.item_list()?; |
101 | 101 | ||
102 | let trait_def = { | 102 | let trait_def = { |
103 | let file_id = ctx.frange.file_id; | 103 | let analyzer = ctx.source_analyzer(impl_node.syntax(), None); |
104 | let analyzer = hir::SourceAnalyzer::new(ctx.db, file_id, impl_node.syntax(), None); | ||
105 | 104 | ||
106 | resolve_target_trait_def(ctx.db, &analyzer, &impl_node)? | 105 | resolve_target_trait_def(ctx.db, &analyzer, &impl_node)? |
107 | }; | 106 | }; |
diff --git a/crates/ra_assists/src/assists/add_new.rs b/crates/ra_assists/src/assists/add_new.rs index a8839cfba..2038afdc6 100644 --- a/crates/ra_assists/src/assists/add_new.rs +++ b/crates/ra_assists/src/assists/add_new.rs | |||
@@ -158,9 +158,12 @@ fn find_struct_impl( | |||
158 | let same_ty = blk.target_ty(db) == struct_ty; | 158 | let same_ty = blk.target_ty(db) == struct_ty; |
159 | let not_trait_impl = blk.target_trait(db).is_none(); | 159 | let not_trait_impl = blk.target_trait(db).is_none(); |
160 | 160 | ||
161 | found_new_fn = has_new_fn(impl_blk); | 161 | if !(same_ty && not_trait_impl) { |
162 | return false; | ||
163 | } | ||
162 | 164 | ||
163 | same_ty && not_trait_impl | 165 | found_new_fn = has_new_fn(impl_blk); |
166 | true | ||
164 | }); | 167 | }); |
165 | 168 | ||
166 | if found_new_fn { | 169 | if found_new_fn { |
@@ -186,9 +189,10 @@ fn has_new_fn(imp: &ast::ImplBlock) -> bool { | |||
186 | 189 | ||
187 | #[cfg(test)] | 190 | #[cfg(test)] |
188 | mod tests { | 191 | mod tests { |
189 | use super::*; | ||
190 | use crate::helpers::{check_assist, check_assist_not_applicable, check_assist_target}; | 192 | use crate::helpers::{check_assist, check_assist_not_applicable, check_assist_target}; |
191 | 193 | ||
194 | use super::*; | ||
195 | |||
192 | #[test] | 196 | #[test] |
193 | #[rustfmt::skip] | 197 | #[rustfmt::skip] |
194 | fn test_add_new() { | 198 | fn test_add_new() { |
@@ -345,7 +349,7 @@ struct Foo {<|>} | |||
345 | impl Foo { | 349 | impl Foo { |
346 | fn new() -> Self { | 350 | fn new() -> Self { |
347 | Self | 351 | Self |
348 | } | 352 | } |
349 | }", | 353 | }", |
350 | ); | 354 | ); |
351 | 355 | ||
@@ -357,7 +361,7 @@ struct Foo {<|>} | |||
357 | impl Foo { | 361 | impl Foo { |
358 | fn New() -> Self { | 362 | fn New() -> Self { |
359 | Self | 363 | Self |
360 | } | 364 | } |
361 | }", | 365 | }", |
362 | ); | 366 | ); |
363 | } | 367 | } |
@@ -376,4 +380,59 @@ struct EvenMoreIrrelevant; | |||
376 | struct Foo<'a, T: Foo<'a>> {}", | 380 | struct Foo<'a, T: Foo<'a>> {}", |
377 | ); | 381 | ); |
378 | } | 382 | } |
383 | |||
384 | #[test] | ||
385 | fn test_unrelated_new() { | ||
386 | check_assist( | ||
387 | add_new, | ||
388 | r##" | ||
389 | pub struct AstId<N: AstNode> { | ||
390 | file_id: HirFileId, | ||
391 | file_ast_id: FileAstId<N>, | ||
392 | } | ||
393 | |||
394 | impl<N: AstNode> AstId<N> { | ||
395 | pub fn new(file_id: HirFileId, file_ast_id: FileAstId<N>) -> AstId<N> { | ||
396 | AstId { file_id, file_ast_id } | ||
397 | } | ||
398 | } | ||
399 | |||
400 | pub struct Source<T> { | ||
401 | pub file_id: HirFileId,<|> | ||
402 | pub ast: T, | ||
403 | } | ||
404 | |||
405 | impl<T> Source<T> { | ||
406 | pub fn map<F: FnOnce(T) -> U, U>(self, f: F) -> Source<U> { | ||
407 | Source { file_id: self.file_id, ast: f(self.ast) } | ||
408 | } | ||
409 | } | ||
410 | "##, | ||
411 | r##" | ||
412 | pub struct AstId<N: AstNode> { | ||
413 | file_id: HirFileId, | ||
414 | file_ast_id: FileAstId<N>, | ||
415 | } | ||
416 | |||
417 | impl<N: AstNode> AstId<N> { | ||
418 | pub fn new(file_id: HirFileId, file_ast_id: FileAstId<N>) -> AstId<N> { | ||
419 | AstId { file_id, file_ast_id } | ||
420 | } | ||
421 | } | ||
422 | |||
423 | pub struct Source<T> { | ||
424 | pub file_id: HirFileId, | ||
425 | pub ast: T, | ||
426 | } | ||
427 | |||
428 | impl<T> Source<T> { | ||
429 | pub fn new(file_id: HirFileId, ast: T) -> Self { Self { file_id, ast } }<|> | ||
430 | |||
431 | pub fn map<F: FnOnce(T) -> U, U>(self, f: F) -> Source<U> { | ||
432 | Source { file_id: self.file_id, ast: f(self.ast) } | ||
433 | } | ||
434 | } | ||
435 | "##, | ||
436 | ); | ||
437 | } | ||
379 | } | 438 | } |
diff --git a/crates/ra_assists/src/assists/fill_match_arms.rs b/crates/ra_assists/src/assists/fill_match_arms.rs index 2b74f355c..b851c2082 100644 --- a/crates/ra_assists/src/assists/fill_match_arms.rs +++ b/crates/ra_assists/src/assists/fill_match_arms.rs | |||
@@ -47,8 +47,7 @@ pub(crate) fn fill_match_arms(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist | |||
47 | 47 | ||
48 | let expr = match_expr.expr()?; | 48 | let expr = match_expr.expr()?; |
49 | let enum_def = { | 49 | let enum_def = { |
50 | let file_id = ctx.frange.file_id; | 50 | let analyzer = ctx.source_analyzer(expr.syntax(), None); |
51 | let analyzer = hir::SourceAnalyzer::new(ctx.db, file_id, expr.syntax(), None); | ||
52 | resolve_enum_def(ctx.db, &analyzer, &expr)? | 51 | resolve_enum_def(ctx.db, &analyzer, &expr)? |
53 | }; | 52 | }; |
54 | let variant_list = enum_def.variant_list()?; | 53 | let variant_list = enum_def.variant_list()?; |
diff --git a/crates/ra_assists/src/assists/inline_local_variable.rs b/crates/ra_assists/src/assists/inline_local_variable.rs index a7fd9b6d2..18a34502c 100644 --- a/crates/ra_assists/src/assists/inline_local_variable.rs +++ b/crates/ra_assists/src/assists/inline_local_variable.rs | |||
@@ -45,7 +45,7 @@ pub(crate) fn inline_local_varialbe(ctx: AssistCtx<impl HirDatabase>) -> Option< | |||
45 | } else { | 45 | } else { |
46 | let_stmt.syntax().text_range() | 46 | let_stmt.syntax().text_range() |
47 | }; | 47 | }; |
48 | let analyzer = hir::SourceAnalyzer::new(ctx.db, ctx.frange.file_id, bind_pat.syntax(), None); | 48 | let analyzer = ctx.source_analyzer(bind_pat.syntax(), None); |
49 | let refs = analyzer.find_all_refs(&bind_pat); | 49 | let refs = analyzer.find_all_refs(&bind_pat); |
50 | 50 | ||
51 | let mut wrap_in_parens = vec![true; refs.len()]; | 51 | let mut wrap_in_parens = vec![true; refs.len()]; |
diff --git a/crates/ra_assists/src/assists/raw_string.rs b/crates/ra_assists/src/assists/raw_string.rs index 58f7157ae..93912a470 100644 --- a/crates/ra_assists/src/assists/raw_string.rs +++ b/crates/ra_assists/src/assists/raw_string.rs | |||
@@ -1,9 +1,9 @@ | |||
1 | use hir::db::HirDatabase; | 1 | use hir::db::HirDatabase; |
2 | use ra_syntax::{ | 2 | use ra_syntax::{ |
3 | ast, AstToken, | ||
3 | SyntaxKind::{RAW_STRING, STRING}, | 4 | SyntaxKind::{RAW_STRING, STRING}, |
4 | TextRange, TextUnit, | 5 | TextUnit, |
5 | }; | 6 | }; |
6 | use rustc_lexer; | ||
7 | 7 | ||
8 | use crate::{Assist, AssistCtx, AssistId}; | 8 | use crate::{Assist, AssistCtx, AssistId}; |
9 | 9 | ||
@@ -23,32 +23,16 @@ use crate::{Assist, AssistCtx, AssistId}; | |||
23 | // } | 23 | // } |
24 | // ``` | 24 | // ``` |
25 | pub(crate) fn make_raw_string(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { | 25 | pub(crate) fn make_raw_string(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { |
26 | let token = ctx.find_token_at_offset(STRING)?; | 26 | let token = ctx.find_token_at_offset(STRING).and_then(ast::String::cast)?; |
27 | let text = token.text().as_str(); | 27 | let value = token.value()?; |
28 | let usual_string_range = find_usual_string_range(text)?; | ||
29 | let start_of_inside = usual_string_range.start().to_usize() + 1; | ||
30 | let end_of_inside = usual_string_range.end().to_usize(); | ||
31 | let inside_str = &text[start_of_inside..end_of_inside]; | ||
32 | let mut unescaped = String::with_capacity(inside_str.len()); | ||
33 | let mut error = Ok(()); | ||
34 | rustc_lexer::unescape::unescape_str( | ||
35 | inside_str, | ||
36 | &mut |_, unescaped_char| match unescaped_char { | ||
37 | Ok(c) => unescaped.push(c), | ||
38 | Err(_) => error = Err(()), | ||
39 | }, | ||
40 | ); | ||
41 | if error.is_err() { | ||
42 | return None; | ||
43 | } | ||
44 | ctx.add_assist(AssistId("make_raw_string"), "make raw string", |edit| { | 28 | ctx.add_assist(AssistId("make_raw_string"), "make raw string", |edit| { |
45 | edit.target(token.text_range()); | 29 | edit.target(token.syntax().text_range()); |
46 | let max_hash_streak = count_hashes(&unescaped); | 30 | let max_hash_streak = count_hashes(&value); |
47 | let mut hashes = String::with_capacity(max_hash_streak + 1); | 31 | let mut hashes = String::with_capacity(max_hash_streak + 1); |
48 | for _ in 0..hashes.capacity() { | 32 | for _ in 0..hashes.capacity() { |
49 | hashes.push('#'); | 33 | hashes.push('#'); |
50 | } | 34 | } |
51 | edit.replace(token.text_range(), format!("r{}\"{}\"{}", hashes, unescaped, hashes)); | 35 | edit.replace(token.syntax().text_range(), format!("r{}\"{}\"{}", hashes, value, hashes)); |
52 | }) | 36 | }) |
53 | } | 37 | } |
54 | 38 | ||
@@ -68,17 +52,13 @@ pub(crate) fn make_raw_string(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist | |||
68 | // } | 52 | // } |
69 | // ``` | 53 | // ``` |
70 | pub(crate) fn make_usual_string(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { | 54 | pub(crate) fn make_usual_string(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { |
71 | let token = ctx.find_token_at_offset(RAW_STRING)?; | 55 | let token = ctx.find_token_at_offset(RAW_STRING).and_then(ast::RawString::cast)?; |
72 | let text = token.text().as_str(); | 56 | let value = token.value()?; |
73 | let usual_string_range = find_usual_string_range(text)?; | ||
74 | ctx.add_assist(AssistId("make_usual_string"), "make usual string", |edit| { | 57 | ctx.add_assist(AssistId("make_usual_string"), "make usual string", |edit| { |
75 | edit.target(token.text_range()); | 58 | edit.target(token.syntax().text_range()); |
76 | // parse inside string to escape `"` | 59 | // parse inside string to escape `"` |
77 | let start_of_inside = usual_string_range.start().to_usize() + 1; | 60 | let escaped = value.escape_default().to_string(); |
78 | let end_of_inside = usual_string_range.end().to_usize(); | 61 | edit.replace(token.syntax().text_range(), format!("\"{}\"", escaped)); |
79 | let inside_str = &text[start_of_inside..end_of_inside]; | ||
80 | let escaped = inside_str.escape_default().to_string(); | ||
81 | edit.replace(token.text_range(), format!("\"{}\"", escaped)); | ||
82 | }) | 62 | }) |
83 | } | 63 | } |
84 | 64 | ||
@@ -132,6 +112,7 @@ pub(crate) fn remove_hash(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { | |||
132 | edit.target(token.text_range()); | 112 | edit.target(token.text_range()); |
133 | let result = &text[2..text.len() - 1]; | 113 | let result = &text[2..text.len() - 1]; |
134 | let result = if result.starts_with('\"') { | 114 | let result = if result.starts_with('\"') { |
115 | // FIXME: this logic is wrong, not only the last has has to handled specially | ||
135 | // no more hash, escape | 116 | // no more hash, escape |
136 | let internal_str = &result[1..result.len() - 1]; | 117 | let internal_str = &result[1..result.len() - 1]; |
137 | format!("\"{}\"", internal_str.escape_default().to_string()) | 118 | format!("\"{}\"", internal_str.escape_default().to_string()) |
@@ -154,20 +135,6 @@ fn count_hashes(s: &str) -> usize { | |||
154 | max_hash_streak | 135 | max_hash_streak |
155 | } | 136 | } |
156 | 137 | ||
157 | fn find_usual_string_range(s: &str) -> Option<TextRange> { | ||
158 | let left_quote = s.find('"')?; | ||
159 | let right_quote = s.rfind('"')?; | ||
160 | if left_quote == right_quote { | ||
161 | // `s` only contains one quote | ||
162 | None | ||
163 | } else { | ||
164 | Some(TextRange::from_to( | ||
165 | TextUnit::from(left_quote as u32), | ||
166 | TextUnit::from(right_quote as u32), | ||
167 | )) | ||
168 | } | ||
169 | } | ||
170 | |||
171 | #[cfg(test)] | 138 | #[cfg(test)] |
172 | mod test { | 139 | mod test { |
173 | use super::*; | 140 | use super::*; |