diff options
Diffstat (limited to 'crates/ra_ide')
-rw-r--r-- | crates/ra_ide/src/display/navigation_target.rs | 10 | ||||
-rw-r--r-- | crates/ra_ide/src/goto_definition.rs | 43 | ||||
-rw-r--r-- | crates/ra_ide/src/inlay_hints.rs | 74 | ||||
-rw-r--r-- | crates/ra_ide/src/marks.rs | 2 | ||||
-rw-r--r-- | crates/ra_ide/src/references/rename.rs | 13 |
5 files changed, 111 insertions, 31 deletions
diff --git a/crates/ra_ide/src/display/navigation_target.rs b/crates/ra_ide/src/display/navigation_target.rs index 914a8b471..de35c6711 100644 --- a/crates/ra_ide/src/display/navigation_target.rs +++ b/crates/ra_ide/src/display/navigation_target.rs | |||
@@ -376,16 +376,20 @@ impl ToNav for hir::Local { | |||
376 | impl ToNav for hir::TypeParam { | 376 | impl ToNav for hir::TypeParam { |
377 | fn to_nav(&self, db: &RootDatabase) -> NavigationTarget { | 377 | fn to_nav(&self, db: &RootDatabase) -> NavigationTarget { |
378 | let src = self.source(db); | 378 | let src = self.source(db); |
379 | let range = match src.value { | 379 | let full_range = match &src.value { |
380 | Either::Left(it) => it.syntax().text_range(), | 380 | Either::Left(it) => it.syntax().text_range(), |
381 | Either::Right(it) => it.syntax().text_range(), | 381 | Either::Right(it) => it.syntax().text_range(), |
382 | }; | 382 | }; |
383 | let focus_range = match &src.value { | ||
384 | Either::Left(_) => None, | ||
385 | Either::Right(it) => it.name().map(|it| it.syntax().text_range()), | ||
386 | }; | ||
383 | NavigationTarget { | 387 | NavigationTarget { |
384 | file_id: src.file_id.original_file(db), | 388 | file_id: src.file_id.original_file(db), |
385 | name: self.name(db).to_string().into(), | 389 | name: self.name(db).to_string().into(), |
386 | kind: TYPE_PARAM, | 390 | kind: TYPE_PARAM, |
387 | full_range: range, | 391 | full_range, |
388 | focus_range: None, | 392 | focus_range, |
389 | container_name: None, | 393 | container_name: None, |
390 | description: None, | 394 | description: None, |
391 | docs: None, | 395 | docs: None, |
diff --git a/crates/ra_ide/src/goto_definition.rs b/crates/ra_ide/src/goto_definition.rs index 1dfca819d..150895abb 100644 --- a/crates/ra_ide/src/goto_definition.rs +++ b/crates/ra_ide/src/goto_definition.rs | |||
@@ -244,6 +244,39 @@ mod tests { | |||
244 | } | 244 | } |
245 | 245 | ||
246 | #[test] | 246 | #[test] |
247 | fn goto_def_for_use_alias() { | ||
248 | covers!(ra_ide_db::goto_def_for_use_alias); | ||
249 | check_goto( | ||
250 | " | ||
251 | //- /lib.rs | ||
252 | use foo as bar<|>; | ||
253 | |||
254 | |||
255 | //- /foo/lib.rs | ||
256 | #[macro_export] | ||
257 | macro_rules! foo { () => { () } }", | ||
258 | "SOURCE_FILE FileId(2) 0..50", | ||
259 | "#[macro_export]\nmacro_rules! foo { () => { () } }\n", | ||
260 | ); | ||
261 | } | ||
262 | |||
263 | #[test] | ||
264 | fn goto_def_for_use_alias_foo_macro() { | ||
265 | check_goto( | ||
266 | " | ||
267 | //- /lib.rs | ||
268 | use foo::foo as bar<|>; | ||
269 | |||
270 | //- /foo/lib.rs | ||
271 | #[macro_export] | ||
272 | macro_rules! foo { () => { () } } | ||
273 | ", | ||
274 | "foo MACRO_CALL FileId(2) 0..49 29..32", | ||
275 | "#[macro_export]\nmacro_rules! foo { () => { () } }|foo", | ||
276 | ); | ||
277 | } | ||
278 | |||
279 | #[test] | ||
247 | fn goto_def_for_macros_in_use_tree() { | 280 | fn goto_def_for_macros_in_use_tree() { |
248 | check_goto( | 281 | check_goto( |
249 | " | 282 | " |
@@ -754,14 +787,14 @@ mod tests { | |||
754 | #[test] | 787 | #[test] |
755 | fn goto_for_type_param() { | 788 | fn goto_for_type_param() { |
756 | check_goto( | 789 | check_goto( |
757 | " | 790 | r#" |
758 | //- /lib.rs | 791 | //- /lib.rs |
759 | struct Foo<T> { | 792 | struct Foo<T: Clone> { |
760 | t: <|>T, | 793 | t: <|>T, |
761 | } | 794 | } |
762 | ", | 795 | "#, |
763 | "T TYPE_PARAM FileId(1) 11..12", | 796 | "T TYPE_PARAM FileId(1) 11..19 11..12", |
764 | "T", | 797 | "T: Clone|T", |
765 | ); | 798 | ); |
766 | } | 799 | } |
767 | 800 | ||
diff --git a/crates/ra_ide/src/inlay_hints.rs b/crates/ra_ide/src/inlay_hints.rs index 98483df32..b391f903a 100644 --- a/crates/ra_ide/src/inlay_hints.rs +++ b/crates/ra_ide/src/inlay_hints.rs | |||
@@ -9,6 +9,7 @@ use ra_syntax::{ | |||
9 | }; | 9 | }; |
10 | 10 | ||
11 | use crate::{FileId, FunctionSignature}; | 11 | use crate::{FileId, FunctionSignature}; |
12 | use stdx::to_lower_snake_case; | ||
12 | 13 | ||
13 | #[derive(Clone, Debug, PartialEq, Eq)] | 14 | #[derive(Clone, Debug, PartialEq, Eq)] |
14 | pub struct InlayHintsConfig { | 15 | pub struct InlayHintsConfig { |
@@ -144,7 +145,7 @@ fn get_param_name_hints( | |||
144 | .iter() | 145 | .iter() |
145 | .skip(n_params_to_skip) | 146 | .skip(n_params_to_skip) |
146 | .zip(args) | 147 | .zip(args) |
147 | .filter(|(param, arg)| should_show_param_hint(&fn_signature, param, &arg)) | 148 | .filter(|(param, arg)| should_show_param_name_hint(sema, &fn_signature, param, &arg)) |
148 | .map(|(param_name, arg)| InlayHint { | 149 | .map(|(param_name, arg)| InlayHint { |
149 | range: arg.syntax().text_range(), | 150 | range: arg.syntax().text_range(), |
150 | kind: InlayKind::ParameterHint, | 151 | kind: InlayKind::ParameterHint, |
@@ -181,7 +182,7 @@ fn get_bind_pat_hints( | |||
181 | 182 | ||
182 | fn pat_is_enum_variant(db: &RootDatabase, bind_pat: &ast::BindPat, pat_ty: &Type) -> bool { | 183 | fn pat_is_enum_variant(db: &RootDatabase, bind_pat: &ast::BindPat, pat_ty: &Type) -> bool { |
183 | if let Some(Adt::Enum(enum_data)) = pat_ty.as_adt() { | 184 | if let Some(Adt::Enum(enum_data)) = pat_ty.as_adt() { |
184 | let pat_text = bind_pat.syntax().to_string(); | 185 | let pat_text = bind_pat.to_string(); |
185 | enum_data | 186 | enum_data |
186 | .variants(db) | 187 | .variants(db) |
187 | .into_iter() | 188 | .into_iter() |
@@ -198,7 +199,7 @@ fn should_not_display_type_hint(db: &RootDatabase, bind_pat: &ast::BindPat, pat_ | |||
198 | } | 199 | } |
199 | 200 | ||
200 | if let Some(Adt::Struct(s)) = pat_ty.as_adt() { | 201 | if let Some(Adt::Struct(s)) = pat_ty.as_adt() { |
201 | if s.fields(db).is_empty() && s.name(db).to_string() == bind_pat.syntax().to_string() { | 202 | if s.fields(db).is_empty() && s.name(db).to_string() == bind_pat.to_string() { |
202 | return true; | 203 | return true; |
203 | } | 204 | } |
204 | } | 205 | } |
@@ -230,15 +231,16 @@ fn should_not_display_type_hint(db: &RootDatabase, bind_pat: &ast::BindPat, pat_ | |||
230 | false | 231 | false |
231 | } | 232 | } |
232 | 233 | ||
233 | fn should_show_param_hint( | 234 | fn should_show_param_name_hint( |
235 | sema: &Semantics<RootDatabase>, | ||
234 | fn_signature: &FunctionSignature, | 236 | fn_signature: &FunctionSignature, |
235 | param_name: &str, | 237 | param_name: &str, |
236 | argument: &ast::Expr, | 238 | argument: &ast::Expr, |
237 | ) -> bool { | 239 | ) -> bool { |
240 | let param_name = param_name.trim_start_matches('_'); | ||
238 | if param_name.is_empty() | 241 | if param_name.is_empty() |
239 | || is_argument_similar_to_param(argument, param_name) | 242 | || Some(param_name) == fn_signature.name.as_ref().map(|s| s.trim_start_matches('_')) |
240 | || Some(param_name.trim_start_matches('_')) | 243 | || is_argument_similar_to_param_name(sema, argument, param_name) |
241 | == fn_signature.name.as_ref().map(|s| s.trim_start_matches('_')) | ||
242 | { | 244 | { |
243 | return false; | 245 | return false; |
244 | } | 246 | } |
@@ -254,20 +256,42 @@ fn should_show_param_hint( | |||
254 | parameters_len != 1 || !is_obvious_param(param_name) | 256 | parameters_len != 1 || !is_obvious_param(param_name) |
255 | } | 257 | } |
256 | 258 | ||
257 | fn is_argument_similar_to_param(argument: &ast::Expr, param_name: &str) -> bool { | 259 | fn is_argument_similar_to_param_name( |
258 | let argument_string = remove_ref(argument.clone()).syntax().to_string(); | 260 | sema: &Semantics<RootDatabase>, |
259 | let param_name = param_name.trim_start_matches('_'); | 261 | argument: &ast::Expr, |
260 | let argument_string = argument_string.trim_start_matches('_'); | 262 | param_name: &str, |
261 | argument_string.starts_with(¶m_name) || argument_string.ends_with(¶m_name) | 263 | ) -> bool { |
264 | if is_enum_name_similar_to_param_name(sema, argument, param_name) { | ||
265 | return true; | ||
266 | } | ||
267 | match get_string_representation(argument) { | ||
268 | None => false, | ||
269 | Some(repr) => { | ||
270 | let argument_string = repr.trim_start_matches('_'); | ||
271 | argument_string.starts_with(param_name) || argument_string.ends_with(param_name) | ||
272 | } | ||
273 | } | ||
274 | } | ||
275 | |||
276 | fn is_enum_name_similar_to_param_name( | ||
277 | sema: &Semantics<RootDatabase>, | ||
278 | argument: &ast::Expr, | ||
279 | param_name: &str, | ||
280 | ) -> bool { | ||
281 | match sema.type_of_expr(argument).and_then(|t| t.as_adt()) { | ||
282 | Some(Adt::Enum(e)) => to_lower_snake_case(&e.name(sema.db).to_string()) == param_name, | ||
283 | _ => false, | ||
284 | } | ||
262 | } | 285 | } |
263 | 286 | ||
264 | fn remove_ref(expr: ast::Expr) -> ast::Expr { | 287 | fn get_string_representation(expr: &ast::Expr) -> Option<String> { |
265 | if let ast::Expr::RefExpr(ref_expr) = &expr { | 288 | match expr { |
266 | if let Some(inner) = ref_expr.expr() { | 289 | ast::Expr::MethodCallExpr(method_call_expr) => { |
267 | return inner; | 290 | Some(method_call_expr.name_ref()?.to_string()) |
268 | } | 291 | } |
292 | ast::Expr::RefExpr(ref_expr) => get_string_representation(&ref_expr.expr()?), | ||
293 | _ => Some(expr.to_string()), | ||
269 | } | 294 | } |
270 | expr | ||
271 | } | 295 | } |
272 | 296 | ||
273 | fn is_obvious_param(param_name: &str) -> bool { | 297 | fn is_obvious_param(param_name: &str) -> bool { |
@@ -1073,6 +1097,12 @@ struct TestVarContainer { | |||
1073 | test_var: i32, | 1097 | test_var: i32, |
1074 | } | 1098 | } |
1075 | 1099 | ||
1100 | impl TestVarContainer { | ||
1101 | fn test_var(&self) -> i32 { | ||
1102 | self.test_var | ||
1103 | } | ||
1104 | } | ||
1105 | |||
1076 | struct Test {} | 1106 | struct Test {} |
1077 | 1107 | ||
1078 | impl Test { | 1108 | impl Test { |
@@ -1098,10 +1128,15 @@ struct Param {} | |||
1098 | fn different_order(param: &Param) {} | 1128 | fn different_order(param: &Param) {} |
1099 | fn different_order_mut(param: &mut Param) {} | 1129 | fn different_order_mut(param: &mut Param) {} |
1100 | fn has_underscore(_param: bool) {} | 1130 | fn has_underscore(_param: bool) {} |
1131 | fn enum_matches_param_name(completion_kind: CompletionKind) {} | ||
1101 | 1132 | ||
1102 | fn twiddle(twiddle: bool) {} | 1133 | fn twiddle(twiddle: bool) {} |
1103 | fn doo(_doo: bool) {} | 1134 | fn doo(_doo: bool) {} |
1104 | 1135 | ||
1136 | enum CompletionKind { | ||
1137 | Keyword, | ||
1138 | } | ||
1139 | |||
1105 | fn main() { | 1140 | fn main() { |
1106 | let container: TestVarContainer = TestVarContainer { test_var: 42 }; | 1141 | let container: TestVarContainer = TestVarContainer { test_var: 42 }; |
1107 | let test: Test = Test {}; | 1142 | let test: Test = Test {}; |
@@ -1114,18 +1149,21 @@ fn main() { | |||
1114 | let test_var: i32 = 55; | 1149 | let test_var: i32 = 55; |
1115 | test_processed.no_hints_expected(22, test_var); | 1150 | test_processed.no_hints_expected(22, test_var); |
1116 | test_processed.no_hints_expected(33, container.test_var); | 1151 | test_processed.no_hints_expected(33, container.test_var); |
1152 | test_processed.no_hints_expected(44, container.test_var()); | ||
1117 | test_processed.frob(false); | 1153 | test_processed.frob(false); |
1118 | 1154 | ||
1119 | twiddle(true); | 1155 | twiddle(true); |
1120 | doo(true); | 1156 | doo(true); |
1121 | 1157 | ||
1122 | let param_begin: Param = Param {}; | 1158 | let mut param_begin: Param = Param {}; |
1123 | different_order(¶m_begin); | 1159 | different_order(¶m_begin); |
1124 | different_order(&mut param_begin); | 1160 | different_order(&mut param_begin); |
1125 | 1161 | ||
1126 | let param: bool = true; | 1162 | let param: bool = true; |
1127 | has_underscore(param); | 1163 | has_underscore(param); |
1128 | 1164 | ||
1165 | enum_matches_param_name(CompletionKind::Keyword); | ||
1166 | |||
1129 | let a: f64 = 7.0; | 1167 | let a: f64 = 7.0; |
1130 | let b: f64 = 4.0; | 1168 | let b: f64 = 4.0; |
1131 | let _: f64 = a.div_euclid(b); | 1169 | let _: f64 = a.div_euclid(b); |
diff --git a/crates/ra_ide/src/marks.rs b/crates/ra_ide/src/marks.rs index bea30fe2a..51ca4dde3 100644 --- a/crates/ra_ide/src/marks.rs +++ b/crates/ra_ide/src/marks.rs | |||
@@ -11,4 +11,6 @@ test_utils::marks!( | |||
11 | self_fulfilling_completion | 11 | self_fulfilling_completion |
12 | test_struct_field_completion_in_func_call | 12 | test_struct_field_completion_in_func_call |
13 | test_struct_field_completion_in_record_lit | 13 | test_struct_field_completion_in_record_lit |
14 | test_rename_struct_field_for_shorthand | ||
15 | test_rename_local_for_field_shorthand | ||
14 | ); | 16 | ); |
diff --git a/crates/ra_ide/src/references/rename.rs b/crates/ra_ide/src/references/rename.rs index fd17bc9f2..916edaef2 100644 --- a/crates/ra_ide/src/references/rename.rs +++ b/crates/ra_ide/src/references/rename.rs | |||
@@ -7,14 +7,13 @@ use ra_syntax::{ | |||
7 | algo::find_node_at_offset, ast, lex_single_valid_syntax_kind, AstNode, SyntaxKind, SyntaxNode, | 7 | algo::find_node_at_offset, ast, lex_single_valid_syntax_kind, AstNode, SyntaxKind, SyntaxNode, |
8 | }; | 8 | }; |
9 | use ra_text_edit::TextEdit; | 9 | use ra_text_edit::TextEdit; |
10 | use test_utils::tested_by; | ||
10 | 11 | ||
11 | use crate::{ | 12 | use crate::{ |
12 | FilePosition, FileSystemEdit, RangeInfo, Reference, ReferenceKind, SourceChange, | 13 | references::find_all_refs, FilePosition, FileSystemEdit, RangeInfo, Reference, ReferenceKind, |
13 | SourceFileEdit, TextRange, | 14 | SourceChange, SourceFileEdit, TextRange, |
14 | }; | 15 | }; |
15 | 16 | ||
16 | use super::find_all_refs; | ||
17 | |||
18 | pub(crate) fn rename( | 17 | pub(crate) fn rename( |
19 | db: &RootDatabase, | 18 | db: &RootDatabase, |
20 | position: FilePosition, | 19 | position: FilePosition, |
@@ -52,11 +51,13 @@ fn source_edit_from_reference(reference: Reference, new_name: &str) -> SourceFil | |||
52 | let file_id = reference.file_range.file_id; | 51 | let file_id = reference.file_range.file_id; |
53 | let range = match reference.kind { | 52 | let range = match reference.kind { |
54 | ReferenceKind::FieldShorthandForField => { | 53 | ReferenceKind::FieldShorthandForField => { |
54 | tested_by!(test_rename_struct_field_for_shorthand); | ||
55 | replacement_text.push_str(new_name); | 55 | replacement_text.push_str(new_name); |
56 | replacement_text.push_str(": "); | 56 | replacement_text.push_str(": "); |
57 | TextRange::new(reference.file_range.range.start(), reference.file_range.range.start()) | 57 | TextRange::new(reference.file_range.range.start(), reference.file_range.range.start()) |
58 | } | 58 | } |
59 | ReferenceKind::FieldShorthandForLocal => { | 59 | ReferenceKind::FieldShorthandForLocal => { |
60 | tested_by!(test_rename_local_for_field_shorthand); | ||
60 | replacement_text.push_str(": "); | 61 | replacement_text.push_str(": "); |
61 | replacement_text.push_str(new_name); | 62 | replacement_text.push_str(new_name); |
62 | TextRange::new(reference.file_range.range.end(), reference.file_range.range.end()) | 63 | TextRange::new(reference.file_range.range.end(), reference.file_range.range.end()) |
@@ -147,7 +148,7 @@ fn rename_reference( | |||
147 | mod tests { | 148 | mod tests { |
148 | use insta::assert_debug_snapshot; | 149 | use insta::assert_debug_snapshot; |
149 | use ra_text_edit::TextEditBuilder; | 150 | use ra_text_edit::TextEditBuilder; |
150 | use test_utils::assert_eq_text; | 151 | use test_utils::{assert_eq_text, covers}; |
151 | 152 | ||
152 | use crate::{ | 153 | use crate::{ |
153 | mock_analysis::analysis_and_position, mock_analysis::single_file_with_position, FileId, | 154 | mock_analysis::analysis_and_position, mock_analysis::single_file_with_position, FileId, |
@@ -379,6 +380,7 @@ mod tests { | |||
379 | 380 | ||
380 | #[test] | 381 | #[test] |
381 | fn test_rename_struct_field_for_shorthand() { | 382 | fn test_rename_struct_field_for_shorthand() { |
383 | covers!(test_rename_struct_field_for_shorthand); | ||
382 | test_rename( | 384 | test_rename( |
383 | r#" | 385 | r#" |
384 | struct Foo { | 386 | struct Foo { |
@@ -408,6 +410,7 @@ mod tests { | |||
408 | 410 | ||
409 | #[test] | 411 | #[test] |
410 | fn test_rename_local_for_field_shorthand() { | 412 | fn test_rename_local_for_field_shorthand() { |
413 | covers!(test_rename_local_for_field_shorthand); | ||
411 | test_rename( | 414 | test_rename( |
412 | r#" | 415 | r#" |
413 | struct Foo { | 416 | struct Foo { |