aboutsummaryrefslogtreecommitdiff
path: root/crates/ide
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ide')
-rw-r--r--crates/ide/src/goto_implementation.rs7
-rw-r--r--crates/ide/src/hover.rs2
-rw-r--r--crates/ide/src/rename.rs46
-rw-r--r--crates/ide/src/typing.rs36
4 files changed, 57 insertions, 34 deletions
diff --git a/crates/ide/src/goto_implementation.rs b/crates/ide/src/goto_implementation.rs
index 0013820b4..07686017d 100644
--- a/crates/ide/src/goto_implementation.rs
+++ b/crates/ide/src/goto_implementation.rs
@@ -236,15 +236,10 @@ impl T for &Foo {}
236 fn goto_implementation_to_builtin_derive() { 236 fn goto_implementation_to_builtin_derive() {
237 check( 237 check(
238 r#" 238 r#"
239//- minicore: copy, derive
239 #[derive(Copy)] 240 #[derive(Copy)]
240//^^^^^^^^^^^^^^^ 241//^^^^^^^^^^^^^^^
241struct Foo$0; 242struct Foo$0;
242
243mod marker {
244 trait Copy {}
245}
246#[rustc_builtin_macro]
247macro Copy {}
248"#, 243"#,
249 ); 244 );
250 } 245 }
diff --git a/crates/ide/src/hover.rs b/crates/ide/src/hover.rs
index 05a2b1293..2e1359eef 100644
--- a/crates/ide/src/hover.rs
+++ b/crates/ide/src/hover.rs
@@ -2258,7 +2258,7 @@ pub fn fo$0o() {}
2258 case 13. collapsed link: foo 2258 case 13. collapsed link: foo
2259 case 14. shortcut link: foo 2259 case 14. shortcut link: foo
2260 case 15. inline without URL: foo 2260 case 15. inline without URL: foo
2261 case 16. just escaped text: \[foo] 2261 case 16. just escaped text: \[foo\]
2262 case 17. inline link: Foo 2262 case 17. inline link: Foo
2263 2263
2264 [^example]: https://www.example.com/ 2264 [^example]: https://www.example.com/
diff --git a/crates/ide/src/rename.rs b/crates/ide/src/rename.rs
index 8096dfa0e..96bd07708 100644
--- a/crates/ide/src/rename.rs
+++ b/crates/ide/src/rename.rs
@@ -10,7 +10,7 @@ use ide_db::{
10 rename::{bail, format_err, source_edit_from_references, IdentifierKind}, 10 rename::{bail, format_err, source_edit_from_references, IdentifierKind},
11 RootDatabase, 11 RootDatabase,
12}; 12};
13use stdx::never; 13use stdx::{always, never};
14use syntax::{ast, AstNode, SyntaxNode}; 14use syntax::{ast, AstNode, SyntaxNode};
15 15
16use text_edit::TextEdit; 16use text_edit::TextEdit;
@@ -31,10 +31,13 @@ pub(crate) fn prepare_rename(
31 let source_file = sema.parse(position.file_id); 31 let source_file = sema.parse(position.file_id);
32 let syntax = source_file.syntax(); 32 let syntax = source_file.syntax();
33 33
34 let def = find_definition(&sema, syntax, position)?; 34 let (name_like, def) = find_definition(&sema, syntax, position)?;
35 let frange = def 35 if def.range_for_rename(&sema).is_none() {
36 .range_for_rename(&sema) 36 bail!("No references found at position")
37 .ok_or_else(|| format_err!("No references found at position"))?; 37 }
38
39 let frange = sema.original_range(name_like.syntax());
40 always!(frange.range.contains_inclusive(position.offset) && frange.file_id == position.file_id);
38 Ok(RangeInfo::new(frange.range, ())) 41 Ok(RangeInfo::new(frange.range, ()))
39} 42}
40 43
@@ -55,31 +58,23 @@ pub(crate) fn rename(
55 new_name: &str, 58 new_name: &str,
56) -> RenameResult<SourceChange> { 59) -> RenameResult<SourceChange> {
57 let sema = Semantics::new(db); 60 let sema = Semantics::new(db);
58 rename_with_semantics(&sema, position, new_name)
59}
60
61pub(crate) fn rename_with_semantics(
62 sema: &Semantics<RootDatabase>,
63 position: FilePosition,
64 new_name: &str,
65) -> RenameResult<SourceChange> {
66 let source_file = sema.parse(position.file_id); 61 let source_file = sema.parse(position.file_id);
67 let syntax = source_file.syntax(); 62 let syntax = source_file.syntax();
68 63
69 let def = find_definition(sema, syntax, position)?; 64 let (_name_like, def) = find_definition(&sema, syntax, position)?;
70 65
71 if let Definition::Local(local) = def { 66 if let Definition::Local(local) = def {
72 if let Some(self_param) = local.as_self_param(sema.db) { 67 if let Some(self_param) = local.as_self_param(sema.db) {
73 cov_mark::hit!(rename_self_to_param); 68 cov_mark::hit!(rename_self_to_param);
74 return rename_self_to_param(sema, local, self_param, new_name); 69 return rename_self_to_param(&sema, local, self_param, new_name);
75 } 70 }
76 if new_name == "self" { 71 if new_name == "self" {
77 cov_mark::hit!(rename_to_self); 72 cov_mark::hit!(rename_to_self);
78 return rename_to_self(sema, local); 73 return rename_to_self(&sema, local);
79 } 74 }
80 } 75 }
81 76
82 def.rename(sema, new_name) 77 def.rename(&sema, new_name)
83} 78}
84 79
85/// Called by the client when it is about to rename a file. 80/// Called by the client when it is about to rename a file.
@@ -100,11 +95,12 @@ fn find_definition(
100 sema: &Semantics<RootDatabase>, 95 sema: &Semantics<RootDatabase>,
101 syntax: &SyntaxNode, 96 syntax: &SyntaxNode,
102 position: FilePosition, 97 position: FilePosition,
103) -> RenameResult<Definition> { 98) -> RenameResult<(ast::NameLike, Definition)> {
104 match sema 99 let name_like = sema
105 .find_node_at_offset_with_descend(syntax, position.offset) 100 .find_node_at_offset_with_descend::<ast::NameLike>(syntax, position.offset)
106 .ok_or_else(|| format_err!("No references found at position"))? 101 .ok_or_else(|| format_err!("No references found at position"))?;
107 { 102
103 let def = match &name_like {
108 // renaming aliases would rename the item being aliased as the HIR doesn't track aliases yet 104 // renaming aliases would rename the item being aliased as the HIR doesn't track aliases yet
109 ast::NameLike::Name(name) 105 ast::NameLike::Name(name)
110 if name.syntax().parent().map_or(false, |it| ast::Rename::can_cast(it.kind())) => 106 if name.syntax().parent().map_or(false, |it| ast::Rename::can_cast(it.kind())) =>
@@ -134,7 +130,9 @@ fn find_definition(
134 .map(|it| it.referenced_or_defined(sema.db)) 130 .map(|it| it.referenced_or_defined(sema.db))
135 }), 131 }),
136 } 132 }
137 .ok_or_else(|| format_err!("No references found at position")) 133 .ok_or_else(|| format_err!("No references found at position"))?;
134
135 Ok((name_like, def))
138} 136}
139 137
140fn rename_to_self(sema: &Semantics<RootDatabase>, local: hir::Local) -> RenameResult<SourceChange> { 138fn rename_to_self(sema: &Semantics<RootDatabase>, local: hir::Local) -> RenameResult<SourceChange> {
@@ -328,7 +326,7 @@ mod tests {
328 fn test_prepare_rename_namelikes() { 326 fn test_prepare_rename_namelikes() {
329 check_prepare(r"fn name$0<'lifetime>() {}", expect![[r#"3..7: name"#]]); 327 check_prepare(r"fn name$0<'lifetime>() {}", expect![[r#"3..7: name"#]]);
330 check_prepare(r"fn name<'lifetime$0>() {}", expect![[r#"8..17: 'lifetime"#]]); 328 check_prepare(r"fn name<'lifetime$0>() {}", expect![[r#"8..17: 'lifetime"#]]);
331 check_prepare(r"fn name<'lifetime>() { name$0(); }", expect![[r#"3..7: name"#]]); 329 check_prepare(r"fn name<'lifetime>() { name$0(); }", expect![[r#"23..27: name"#]]);
332 } 330 }
333 331
334 #[test] 332 #[test]
diff --git a/crates/ide/src/typing.rs b/crates/ide/src/typing.rs
index 4ad49eca0..37ae92350 100644
--- a/crates/ide/src/typing.rs
+++ b/crates/ide/src/typing.rs
@@ -23,7 +23,7 @@ use syntax::{
23 algo::find_node_at_offset, 23 algo::find_node_at_offset,
24 ast::{self, edit::IndentLevel, AstToken}, 24 ast::{self, edit::IndentLevel, AstToken},
25 AstNode, Parse, SourceFile, 25 AstNode, Parse, SourceFile,
26 SyntaxKind::{FIELD_EXPR, METHOD_CALL_EXPR}, 26 SyntaxKind::{self, FIELD_EXPR, METHOD_CALL_EXPR},
27 TextRange, TextSize, 27 TextRange, TextSize,
28}; 28};
29 29
@@ -95,9 +95,16 @@ fn on_opening_brace_typed(file: &Parse<SourceFile>, offset: TextSize) -> Option<
95 } 95 }
96 96
97 let brace_token = file.tree().syntax().token_at_offset(offset).right_biased()?; 97 let brace_token = file.tree().syntax().token_at_offset(offset).right_biased()?;
98 if brace_token.kind() != SyntaxKind::L_CURLY {
99 return None;
100 }
98 101
99 // Remove the `{` to get a better parse tree, and reparse 102 // Remove the `{` to get a better parse tree, and reparse.
100 let file = file.reparse(&Indel::delete(brace_token.text_range())); 103 let range = brace_token.text_range();
104 if !stdx::always!(range.len() == TextSize::of('{')) {
105 return None;
106 }
107 let file = file.reparse(&Indel::delete(range));
101 108
102 if let Some(edit) = brace_expr(&file.tree(), offset) { 109 if let Some(edit) = brace_expr(&file.tree(), offset) {
103 return Some(edit); 110 return Some(edit);
@@ -550,6 +557,29 @@ fn f() {
550 } 557 }
551 558
552 #[test] 559 #[test]
560 fn noop_in_string_literal() {
561 // Regression test for #9351
562 type_char_noop(
563 '{',
564 r##"
565fn check_with(ra_fixture: &str, expect: Expect) {
566 let base = r#"
567enum E { T(), R$0, C }
568use self::E::X;
569const Z: E = E::C;
570mod m {}
571asdasdasdasdasdasda
572sdasdasdasdasdasda
573sdasdasdasdasd
574"#;
575 let actual = completion_list(&format!("{}\n{}", base, ra_fixture));
576 expect.assert_eq(&actual)
577}
578 "##,
579 );
580 }
581
582 #[test]
553 fn adds_closing_brace_for_use_tree() { 583 fn adds_closing_brace_for_use_tree() {
554 type_char( 584 type_char(
555 '{', 585 '{',