diff options
Diffstat (limited to 'crates')
-rw-r--r-- | crates/assists/src/handlers/fix_visibility.rs | 10 | ||||
-rw-r--r-- | crates/hir/src/semantics/source_to_def.rs | 4 | ||||
-rw-r--r-- | crates/hir_def/src/adt.rs | 28 | ||||
-rw-r--r-- | crates/hir_ty/Cargo.toml | 6 | ||||
-rw-r--r-- | crates/ide/src/completion/complete_postfix/format_like.rs | 2 | ||||
-rw-r--r-- | crates/ide/src/lib.rs | 6 | ||||
-rw-r--r-- | crates/ide/src/references.rs | 88 | ||||
-rw-r--r-- | crates/ide/src/references/rename.rs | 175 | ||||
-rw-r--r-- | crates/ide_db/src/search.rs | 116 | ||||
-rw-r--r-- | crates/proc_macro_srv/src/proc_macro/bridge/client.rs | 1 | ||||
-rw-r--r-- | crates/proc_macro_srv/src/proc_macro/bridge/mod.rs | 4 | ||||
-rw-r--r-- | crates/proc_macro_srv/src/proc_macro/bridge/server.rs | 2 | ||||
-rw-r--r-- | crates/proc_macro_srv/src/proc_macro/mod.rs | 22 | ||||
-rw-r--r-- | crates/proc_macro_srv/src/rustc_server.rs | 10 | ||||
-rw-r--r-- | crates/profile/Cargo.toml | 2 | ||||
-rw-r--r-- | crates/project_model/src/sysroot.rs | 10 | ||||
-rw-r--r-- | crates/rust-analyzer/src/handlers.rs | 17 | ||||
-rw-r--r-- | crates/syntax/Cargo.toml | 2 |
18 files changed, 379 insertions, 126 deletions
diff --git a/crates/assists/src/handlers/fix_visibility.rs b/crates/assists/src/handlers/fix_visibility.rs index 7cd76ea06..d505e9444 100644 --- a/crates/assists/src/handlers/fix_visibility.rs +++ b/crates/assists/src/handlers/fix_visibility.rs | |||
@@ -324,14 +324,14 @@ pub struct Foo { pub bar: () } | |||
324 | 324 | ||
325 | #[test] | 325 | #[test] |
326 | fn fix_visibility_of_enum_variant_field() { | 326 | fn fix_visibility_of_enum_variant_field() { |
327 | check_assist( | 327 | // Enum variants, as well as their fields, always get the enum's visibility. In fact, rustc |
328 | // rejects any visibility specifiers on them, so this assist should never fire on them. | ||
329 | check_assist_not_applicable( | ||
328 | fix_visibility, | 330 | fix_visibility, |
329 | r"mod foo { pub enum Foo { Bar { bar: () } } } | 331 | r"mod foo { pub enum Foo { Bar { bar: () } } } |
330 | fn main() { foo::Foo::Bar { <|>bar: () }; } ", | 332 | fn main() { foo::Foo::Bar { <|>bar: () }; } ", |
331 | r"mod foo { pub enum Foo { Bar { $0pub(crate) bar: () } } } | ||
332 | fn main() { foo::Foo::Bar { bar: () }; } ", | ||
333 | ); | 333 | ); |
334 | check_assist( | 334 | check_assist_not_applicable( |
335 | fix_visibility, | 335 | fix_visibility, |
336 | r" | 336 | r" |
337 | //- /lib.rs | 337 | //- /lib.rs |
@@ -340,8 +340,6 @@ fn main() { foo::Foo::Bar { <|>bar: () }; } | |||
340 | //- /foo.rs | 340 | //- /foo.rs |
341 | pub enum Foo { Bar { bar: () } } | 341 | pub enum Foo { Bar { bar: () } } |
342 | ", | 342 | ", |
343 | r"pub enum Foo { Bar { $0pub(crate) bar: () } } | ||
344 | ", | ||
345 | ); | 343 | ); |
346 | check_assist_not_applicable( | 344 | check_assist_not_applicable( |
347 | fix_visibility, | 345 | fix_visibility, |
diff --git a/crates/hir/src/semantics/source_to_def.rs b/crates/hir/src/semantics/source_to_def.rs index 5918b9541..66fc11611 100644 --- a/crates/hir/src/semantics/source_to_def.rs +++ b/crates/hir/src/semantics/source_to_def.rs | |||
@@ -189,6 +189,10 @@ impl SourceToDefCtx<'_, '_> { | |||
189 | let def = self.type_alias_to_def(container.with_value(it))?; | 189 | let def = self.type_alias_to_def(container.with_value(it))?; |
190 | def.into() | 190 | def.into() |
191 | }, | 191 | }, |
192 | ast::Variant(it) => { | ||
193 | let def = self.enum_variant_to_def(container.with_value(it))?; | ||
194 | VariantId::from(def).into() | ||
195 | }, | ||
192 | _ => continue, | 196 | _ => continue, |
193 | } | 197 | } |
194 | }; | 198 | }; |
diff --git a/crates/hir_def/src/adt.rs b/crates/hir_def/src/adt.rs index d69ff2fc7..6539959c3 100644 --- a/crates/hir_def/src/adt.rs +++ b/crates/hir_def/src/adt.rs | |||
@@ -14,7 +14,7 @@ use tt::{Delimiter, DelimiterKind, Leaf, Subtree, TokenTree}; | |||
14 | use crate::{ | 14 | use crate::{ |
15 | body::{CfgExpander, LowerCtx}, | 15 | body::{CfgExpander, LowerCtx}, |
16 | db::DefDatabase, | 16 | db::DefDatabase, |
17 | item_tree::{AttrOwner, Field, Fields, ItemTree, ModItem}, | 17 | item_tree::{AttrOwner, Field, Fields, ItemTree, ModItem, RawVisibilityId}, |
18 | src::HasChildSource, | 18 | src::HasChildSource, |
19 | src::HasSource, | 19 | src::HasSource, |
20 | trace::Trace, | 20 | trace::Trace, |
@@ -91,7 +91,7 @@ impl StructData { | |||
91 | let cfg_options = db.crate_graph()[loc.container.module(db).krate].cfg_options.clone(); | 91 | let cfg_options = db.crate_graph()[loc.container.module(db).krate].cfg_options.clone(); |
92 | 92 | ||
93 | let strukt = &item_tree[loc.id.value]; | 93 | let strukt = &item_tree[loc.id.value]; |
94 | let variant_data = lower_fields(&item_tree, &cfg_options, &strukt.fields); | 94 | let variant_data = lower_fields(&item_tree, &cfg_options, &strukt.fields, None); |
95 | Arc::new(StructData { | 95 | Arc::new(StructData { |
96 | name: strukt.name.clone(), | 96 | name: strukt.name.clone(), |
97 | variant_data: Arc::new(variant_data), | 97 | variant_data: Arc::new(variant_data), |
@@ -105,7 +105,7 @@ impl StructData { | |||
105 | let cfg_options = db.crate_graph()[loc.container.module(db).krate].cfg_options.clone(); | 105 | let cfg_options = db.crate_graph()[loc.container.module(db).krate].cfg_options.clone(); |
106 | 106 | ||
107 | let union = &item_tree[loc.id.value]; | 107 | let union = &item_tree[loc.id.value]; |
108 | let variant_data = lower_fields(&item_tree, &cfg_options, &union.fields); | 108 | let variant_data = lower_fields(&item_tree, &cfg_options, &union.fields, None); |
109 | 109 | ||
110 | Arc::new(StructData { | 110 | Arc::new(StructData { |
111 | name: union.name.clone(), | 111 | name: union.name.clone(), |
@@ -126,7 +126,8 @@ impl EnumData { | |||
126 | for var_id in enum_.variants.clone() { | 126 | for var_id in enum_.variants.clone() { |
127 | if item_tree.attrs(var_id.into()).is_cfg_enabled(&cfg_options) { | 127 | if item_tree.attrs(var_id.into()).is_cfg_enabled(&cfg_options) { |
128 | let var = &item_tree[var_id]; | 128 | let var = &item_tree[var_id]; |
129 | let var_data = lower_fields(&item_tree, &cfg_options, &var.fields); | 129 | let var_data = |
130 | lower_fields(&item_tree, &cfg_options, &var.fields, Some(enum_.visibility)); | ||
130 | 131 | ||
131 | variants.alloc(EnumVariantData { | 132 | variants.alloc(EnumVariantData { |
132 | name: var.name.clone(), | 133 | name: var.name.clone(), |
@@ -296,13 +297,18 @@ fn lower_struct( | |||
296 | } | 297 | } |
297 | } | 298 | } |
298 | 299 | ||
299 | fn lower_fields(item_tree: &ItemTree, cfg_options: &CfgOptions, fields: &Fields) -> VariantData { | 300 | fn lower_fields( |
301 | item_tree: &ItemTree, | ||
302 | cfg_options: &CfgOptions, | ||
303 | fields: &Fields, | ||
304 | override_visibility: Option<RawVisibilityId>, | ||
305 | ) -> VariantData { | ||
300 | match fields { | 306 | match fields { |
301 | Fields::Record(flds) => { | 307 | Fields::Record(flds) => { |
302 | let mut arena = Arena::new(); | 308 | let mut arena = Arena::new(); |
303 | for field_id in flds.clone() { | 309 | for field_id in flds.clone() { |
304 | if item_tree.attrs(field_id.into()).is_cfg_enabled(cfg_options) { | 310 | if item_tree.attrs(field_id.into()).is_cfg_enabled(cfg_options) { |
305 | arena.alloc(lower_field(item_tree, &item_tree[field_id])); | 311 | arena.alloc(lower_field(item_tree, &item_tree[field_id], override_visibility)); |
306 | } | 312 | } |
307 | } | 313 | } |
308 | VariantData::Record(arena) | 314 | VariantData::Record(arena) |
@@ -311,7 +317,7 @@ fn lower_fields(item_tree: &ItemTree, cfg_options: &CfgOptions, fields: &Fields) | |||
311 | let mut arena = Arena::new(); | 317 | let mut arena = Arena::new(); |
312 | for field_id in flds.clone() { | 318 | for field_id in flds.clone() { |
313 | if item_tree.attrs(field_id.into()).is_cfg_enabled(cfg_options) { | 319 | if item_tree.attrs(field_id.into()).is_cfg_enabled(cfg_options) { |
314 | arena.alloc(lower_field(item_tree, &item_tree[field_id])); | 320 | arena.alloc(lower_field(item_tree, &item_tree[field_id], override_visibility)); |
315 | } | 321 | } |
316 | } | 322 | } |
317 | VariantData::Tuple(arena) | 323 | VariantData::Tuple(arena) |
@@ -320,10 +326,14 @@ fn lower_fields(item_tree: &ItemTree, cfg_options: &CfgOptions, fields: &Fields) | |||
320 | } | 326 | } |
321 | } | 327 | } |
322 | 328 | ||
323 | fn lower_field(item_tree: &ItemTree, field: &Field) -> FieldData { | 329 | fn lower_field( |
330 | item_tree: &ItemTree, | ||
331 | field: &Field, | ||
332 | override_visibility: Option<RawVisibilityId>, | ||
333 | ) -> FieldData { | ||
324 | FieldData { | 334 | FieldData { |
325 | name: field.name.clone(), | 335 | name: field.name.clone(), |
326 | type_ref: field.type_ref.clone(), | 336 | type_ref: field.type_ref.clone(), |
327 | visibility: item_tree[field.visibility].clone(), | 337 | visibility: item_tree[override_visibility.unwrap_or(field.visibility)].clone(), |
328 | } | 338 | } |
329 | } | 339 | } |
diff --git a/crates/hir_ty/Cargo.toml b/crates/hir_ty/Cargo.toml index 0f3c85926..e9c62c6aa 100644 --- a/crates/hir_ty/Cargo.toml +++ b/crates/hir_ty/Cargo.toml | |||
@@ -17,9 +17,9 @@ ena = "0.14.0" | |||
17 | log = "0.4.8" | 17 | log = "0.4.8" |
18 | rustc-hash = "1.1.0" | 18 | rustc-hash = "1.1.0" |
19 | scoped-tls = "1" | 19 | scoped-tls = "1" |
20 | chalk-solve = "0.32" | 20 | chalk-solve = "0.33" |
21 | chalk-ir = "0.32" | 21 | chalk-ir = "0.33" |
22 | chalk-recursive = "0.32" | 22 | chalk-recursive = "0.33" |
23 | 23 | ||
24 | stdx = { path = "../stdx", version = "0.0.0" } | 24 | stdx = { path = "../stdx", version = "0.0.0" } |
25 | hir_def = { path = "../hir_def", version = "0.0.0" } | 25 | hir_def = { path = "../hir_def", version = "0.0.0" } |
diff --git a/crates/ide/src/completion/complete_postfix/format_like.rs b/crates/ide/src/completion/complete_postfix/format_like.rs index 81c33bf3a..50d1e5c81 100644 --- a/crates/ide/src/completion/complete_postfix/format_like.rs +++ b/crates/ide/src/completion/complete_postfix/format_like.rs | |||
@@ -25,6 +25,7 @@ static KINDS: &[(&str, &str)] = &[ | |||
25 | ("fmt", "format!"), | 25 | ("fmt", "format!"), |
26 | ("panic", "panic!"), | 26 | ("panic", "panic!"), |
27 | ("println", "println!"), | 27 | ("println", "println!"), |
28 | ("eprintln", "eprintln!"), | ||
28 | ("logd", "log::debug!"), | 29 | ("logd", "log::debug!"), |
29 | ("logt", "log::trace!"), | 30 | ("logt", "log::trace!"), |
30 | ("logi", "log::info!"), | 31 | ("logi", "log::info!"), |
@@ -259,6 +260,7 @@ mod tests { | |||
259 | fn test_into_suggestion() { | 260 | fn test_into_suggestion() { |
260 | let test_vector = &[ | 261 | let test_vector = &[ |
261 | ("println!", "{}", r#"println!("{}", $1)"#), | 262 | ("println!", "{}", r#"println!("{}", $1)"#), |
263 | ("eprintln!", "{}", r#"eprintln!("{}", $1)"#), | ||
262 | ( | 264 | ( |
263 | "log::info!", | 265 | "log::info!", |
264 | "{} {expr} {} {2 + 2}", | 266 | "{} {expr} {} {2 + 2}", |
diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs index 5db6e1311..686cee3a1 100644 --- a/crates/ide/src/lib.rs +++ b/crates/ide/src/lib.rs | |||
@@ -77,7 +77,9 @@ pub use crate::{ | |||
77 | hover::{HoverAction, HoverConfig, HoverGotoTypeData, HoverResult}, | 77 | hover::{HoverAction, HoverConfig, HoverGotoTypeData, HoverResult}, |
78 | inlay_hints::{InlayHint, InlayHintsConfig, InlayKind}, | 78 | inlay_hints::{InlayHint, InlayHintsConfig, InlayKind}, |
79 | markup::Markup, | 79 | markup::Markup, |
80 | references::{Declaration, Reference, ReferenceAccess, ReferenceKind, ReferenceSearchResult}, | 80 | references::{ |
81 | Declaration, Reference, ReferenceAccess, ReferenceKind, ReferenceSearchResult, RenameError, | ||
82 | }, | ||
81 | runnables::{Runnable, RunnableKind, TestId}, | 83 | runnables::{Runnable, RunnableKind, TestId}, |
82 | syntax_highlighting::{ | 84 | syntax_highlighting::{ |
83 | Highlight, HighlightModifier, HighlightModifiers, HighlightTag, HighlightedRange, | 85 | Highlight, HighlightModifier, HighlightModifiers, HighlightTag, HighlightedRange, |
@@ -498,7 +500,7 @@ impl Analysis { | |||
498 | &self, | 500 | &self, |
499 | position: FilePosition, | 501 | position: FilePosition, |
500 | new_name: &str, | 502 | new_name: &str, |
501 | ) -> Cancelable<Option<RangeInfo<SourceChange>>> { | 503 | ) -> Cancelable<Result<RangeInfo<SourceChange>, RenameError>> { |
502 | self.with_db(|db| references::rename(db, position, new_name)) | 504 | self.with_db(|db| references::rename(db, position, new_name)) |
503 | } | 505 | } |
504 | 506 | ||
diff --git a/crates/ide/src/references.rs b/crates/ide/src/references.rs index e0830eb4f..f65a05ea3 100644 --- a/crates/ide/src/references.rs +++ b/crates/ide/src/references.rs | |||
@@ -26,6 +26,7 @@ use syntax::{ | |||
26 | use crate::{display::TryToNav, FilePosition, FileRange, NavigationTarget, RangeInfo}; | 26 | use crate::{display::TryToNav, FilePosition, FileRange, NavigationTarget, RangeInfo}; |
27 | 27 | ||
28 | pub(crate) use self::rename::rename; | 28 | pub(crate) use self::rename::rename; |
29 | pub use self::rename::RenameError; | ||
29 | 30 | ||
30 | pub use ide_db::search::{Reference, ReferenceAccess, ReferenceKind}; | 31 | pub use ide_db::search::{Reference, ReferenceAccess, ReferenceKind}; |
31 | 32 | ||
@@ -406,6 +407,23 @@ enum Foo { | |||
406 | } | 407 | } |
407 | 408 | ||
408 | #[test] | 409 | #[test] |
410 | fn test_find_all_refs_enum_var_field() { | ||
411 | check( | ||
412 | r#" | ||
413 | enum Foo { | ||
414 | A, | ||
415 | B { field<|>: u8 }, | ||
416 | C, | ||
417 | } | ||
418 | "#, | ||
419 | expect![[r#" | ||
420 | field RECORD_FIELD FileId(0) 26..35 26..31 Other | ||
421 | |||
422 | "#]], | ||
423 | ); | ||
424 | } | ||
425 | |||
426 | #[test] | ||
409 | fn test_find_all_refs_two_modules() { | 427 | fn test_find_all_refs_two_modules() { |
410 | check( | 428 | check( |
411 | r#" | 429 | r#" |
@@ -669,6 +687,76 @@ fn g() { f(); } | |||
669 | ); | 687 | ); |
670 | } | 688 | } |
671 | 689 | ||
690 | #[test] | ||
691 | fn test_find_all_refs_struct_pat() { | ||
692 | check( | ||
693 | r#" | ||
694 | struct S { | ||
695 | field<|>: u8, | ||
696 | } | ||
697 | |||
698 | fn f(s: S) { | ||
699 | match s { | ||
700 | S { field } => {} | ||
701 | } | ||
702 | } | ||
703 | "#, | ||
704 | expect![[r#" | ||
705 | field RECORD_FIELD FileId(0) 15..24 15..20 Other | ||
706 | |||
707 | FileId(0) 68..73 FieldShorthandForField Read | ||
708 | "#]], | ||
709 | ); | ||
710 | } | ||
711 | |||
712 | #[test] | ||
713 | fn test_find_all_refs_enum_var_pat() { | ||
714 | check( | ||
715 | r#" | ||
716 | enum En { | ||
717 | Variant { | ||
718 | field<|>: u8, | ||
719 | } | ||
720 | } | ||
721 | |||
722 | fn f(e: En) { | ||
723 | match e { | ||
724 | En::Variant { field } => {} | ||
725 | } | ||
726 | } | ||
727 | "#, | ||
728 | expect![[r#" | ||
729 | field RECORD_FIELD FileId(0) 32..41 32..37 Other | ||
730 | |||
731 | FileId(0) 102..107 FieldShorthandForField Read | ||
732 | "#]], | ||
733 | ); | ||
734 | } | ||
735 | |||
736 | #[test] | ||
737 | fn test_find_all_refs_enum_var_privacy() { | ||
738 | check( | ||
739 | r#" | ||
740 | mod m { | ||
741 | pub enum En { | ||
742 | Variant { | ||
743 | field<|>: u8, | ||
744 | } | ||
745 | } | ||
746 | } | ||
747 | |||
748 | fn f() -> m::En { | ||
749 | m::En::Variant { field: 0 } | ||
750 | } | ||
751 | "#, | ||
752 | expect![[r#" | ||
753 | field RECORD_FIELD FileId(0) 56..65 56..61 Other | ||
754 | |||
755 | FileId(0) 125..130 Other Read | ||
756 | "#]], | ||
757 | ); | ||
758 | } | ||
759 | |||
672 | fn check(ra_fixture: &str, expect: Expect) { | 760 | fn check(ra_fixture: &str, expect: Expect) { |
673 | check_with_scope(ra_fixture, None, expect) | 761 | check_with_scope(ra_fixture, None, expect) |
674 | } | 762 | } |
diff --git a/crates/ide/src/references/rename.rs b/crates/ide/src/references/rename.rs index 8cbe1ae5a..f3b5cfc8c 100644 --- a/crates/ide/src/references/rename.rs +++ b/crates/ide/src/references/rename.rs | |||
@@ -6,11 +6,16 @@ use ide_db::{ | |||
6 | defs::{classify_name, classify_name_ref, Definition, NameClass, NameRefClass}, | 6 | defs::{classify_name, classify_name_ref, Definition, NameClass, NameRefClass}, |
7 | RootDatabase, | 7 | RootDatabase, |
8 | }; | 8 | }; |
9 | use std::convert::TryInto; | 9 | |
10 | use std::{ | ||
11 | convert::TryInto, | ||
12 | error::Error, | ||
13 | fmt::{self, Display}, | ||
14 | }; | ||
10 | use syntax::{ | 15 | use syntax::{ |
11 | algo::find_node_at_offset, | 16 | algo::find_node_at_offset, |
12 | ast::{self, NameOwner}, | 17 | ast::{self, NameOwner}, |
13 | lex_single_valid_syntax_kind, match_ast, AstNode, SyntaxKind, SyntaxNode, SyntaxToken, | 18 | lex_single_syntax_kind, match_ast, AstNode, SyntaxKind, SyntaxNode, SyntaxToken, |
14 | }; | 19 | }; |
15 | use test_utils::mark; | 20 | use test_utils::mark; |
16 | use text_edit::TextEdit; | 21 | use text_edit::TextEdit; |
@@ -20,17 +25,37 @@ use crate::{ | |||
20 | SourceChange, SourceFileEdit, TextRange, TextSize, | 25 | SourceChange, SourceFileEdit, TextRange, TextSize, |
21 | }; | 26 | }; |
22 | 27 | ||
28 | #[derive(Debug)] | ||
29 | pub struct RenameError(pub(crate) String); | ||
30 | |||
31 | impl fmt::Display for RenameError { | ||
32 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||
33 | Display::fmt(&self.0, f) | ||
34 | } | ||
35 | } | ||
36 | |||
37 | impl Error for RenameError {} | ||
38 | |||
23 | pub(crate) fn rename( | 39 | pub(crate) fn rename( |
24 | db: &RootDatabase, | 40 | db: &RootDatabase, |
25 | position: FilePosition, | 41 | position: FilePosition, |
26 | new_name: &str, | 42 | new_name: &str, |
27 | ) -> Option<RangeInfo<SourceChange>> { | 43 | ) -> Result<RangeInfo<SourceChange>, RenameError> { |
28 | let sema = Semantics::new(db); | 44 | let sema = Semantics::new(db); |
29 | 45 | ||
30 | match lex_single_valid_syntax_kind(new_name)? { | 46 | match lex_single_syntax_kind(new_name) { |
31 | SyntaxKind::IDENT | SyntaxKind::UNDERSCORE => (), | 47 | Some(res) => match res { |
32 | SyntaxKind::SELF_KW => return rename_to_self(&sema, position), | 48 | (SyntaxKind::IDENT, _) => (), |
33 | _ => return None, | 49 | (SyntaxKind::UNDERSCORE, _) => (), |
50 | (SyntaxKind::SELF_KW, _) => return rename_to_self(&sema, position), | ||
51 | (_, Some(syntax_error)) => { | ||
52 | return Err(RenameError(format!("Invalid name `{}`: {}", new_name, syntax_error))) | ||
53 | } | ||
54 | (_, None) => { | ||
55 | return Err(RenameError(format!("Invalid name `{}`: not an identifier", new_name))) | ||
56 | } | ||
57 | }, | ||
58 | None => return Err(RenameError(format!("Invalid name `{}`: not an identifier", new_name))), | ||
34 | } | 59 | } |
35 | 60 | ||
36 | let source_file = sema.parse(position.file_id); | 61 | let source_file = sema.parse(position.file_id); |
@@ -103,7 +128,7 @@ fn rename_mod( | |||
103 | position: FilePosition, | 128 | position: FilePosition, |
104 | module: Module, | 129 | module: Module, |
105 | new_name: &str, | 130 | new_name: &str, |
106 | ) -> Option<RangeInfo<SourceChange>> { | 131 | ) -> Result<RangeInfo<SourceChange>, RenameError> { |
107 | let mut source_file_edits = Vec::new(); | 132 | let mut source_file_edits = Vec::new(); |
108 | let mut file_system_edits = Vec::new(); | 133 | let mut file_system_edits = Vec::new(); |
109 | 134 | ||
@@ -125,7 +150,7 @@ fn rename_mod( | |||
125 | 150 | ||
126 | if let Some(src) = module.declaration_source(sema.db) { | 151 | if let Some(src) = module.declaration_source(sema.db) { |
127 | let file_id = src.file_id.original_file(sema.db); | 152 | let file_id = src.file_id.original_file(sema.db); |
128 | let name = src.value.name()?; | 153 | let name = src.value.name().unwrap(); |
129 | let edit = SourceFileEdit { | 154 | let edit = SourceFileEdit { |
130 | file_id, | 155 | file_id, |
131 | edit: TextEdit::replace(name.syntax().text_range(), new_name.into()), | 156 | edit: TextEdit::replace(name.syntax().text_range(), new_name.into()), |
@@ -133,35 +158,40 @@ fn rename_mod( | |||
133 | source_file_edits.push(edit); | 158 | source_file_edits.push(edit); |
134 | } | 159 | } |
135 | 160 | ||
136 | let RangeInfo { range, info: refs } = find_all_refs(sema, position, None)?; | 161 | let RangeInfo { range, info: refs } = find_all_refs(sema, position, None) |
162 | .ok_or_else(|| RenameError("No references found at position".to_string()))?; | ||
137 | let ref_edits = refs | 163 | let ref_edits = refs |
138 | .references | 164 | .references |
139 | .into_iter() | 165 | .into_iter() |
140 | .map(|reference| source_edit_from_reference(reference, new_name)); | 166 | .map(|reference| source_edit_from_reference(reference, new_name)); |
141 | source_file_edits.extend(ref_edits); | 167 | source_file_edits.extend(ref_edits); |
142 | 168 | ||
143 | Some(RangeInfo::new(range, SourceChange::from_edits(source_file_edits, file_system_edits))) | 169 | Ok(RangeInfo::new(range, SourceChange::from_edits(source_file_edits, file_system_edits))) |
144 | } | 170 | } |
145 | 171 | ||
146 | fn rename_to_self( | 172 | fn rename_to_self( |
147 | sema: &Semantics<RootDatabase>, | 173 | sema: &Semantics<RootDatabase>, |
148 | position: FilePosition, | 174 | position: FilePosition, |
149 | ) -> Option<RangeInfo<SourceChange>> { | 175 | ) -> Result<RangeInfo<SourceChange>, RenameError> { |
150 | let source_file = sema.parse(position.file_id); | 176 | let source_file = sema.parse(position.file_id); |
151 | let syn = source_file.syntax(); | 177 | let syn = source_file.syntax(); |
152 | 178 | ||
153 | let fn_def = find_node_at_offset::<ast::Fn>(syn, position.offset)?; | 179 | let fn_def = find_node_at_offset::<ast::Fn>(syn, position.offset) |
154 | let params = fn_def.param_list()?; | 180 | .ok_or_else(|| RenameError("No surrounding method declaration found".to_string()))?; |
181 | let params = | ||
182 | fn_def.param_list().ok_or_else(|| RenameError("Method has no parameters".to_string()))?; | ||
155 | if params.self_param().is_some() { | 183 | if params.self_param().is_some() { |
156 | return None; // method already has self param | 184 | return Err(RenameError("Method already has a self parameter".to_string())); |
157 | } | 185 | } |
158 | let first_param = params.params().next()?; | 186 | let first_param = |
187 | params.params().next().ok_or_else(|| RenameError("Method has no parameters".into()))?; | ||
159 | let mutable = match first_param.ty() { | 188 | let mutable = match first_param.ty() { |
160 | Some(ast::Type::RefType(rt)) => rt.mut_token().is_some(), | 189 | Some(ast::Type::RefType(rt)) => rt.mut_token().is_some(), |
161 | _ => return None, // not renaming other types | 190 | _ => return Err(RenameError("Not renaming other types".to_string())), |
162 | }; | 191 | }; |
163 | 192 | ||
164 | let RangeInfo { range, info: refs } = find_all_refs(sema, position, None)?; | 193 | let RangeInfo { range, info: refs } = find_all_refs(sema, position, None) |
194 | .ok_or_else(|| RenameError("No reference found at position".to_string()))?; | ||
165 | 195 | ||
166 | let param_range = first_param.syntax().text_range(); | 196 | let param_range = first_param.syntax().text_range(); |
167 | let (param_ref, usages): (Vec<Reference>, Vec<Reference>) = refs | 197 | let (param_ref, usages): (Vec<Reference>, Vec<Reference>) = refs |
@@ -169,7 +199,7 @@ fn rename_to_self( | |||
169 | .partition(|reference| param_range.intersect(reference.file_range.range).is_some()); | 199 | .partition(|reference| param_range.intersect(reference.file_range.range).is_some()); |
170 | 200 | ||
171 | if param_ref.is_empty() { | 201 | if param_ref.is_empty() { |
172 | return None; | 202 | return Err(RenameError("Parameter to rename not found".to_string())); |
173 | } | 203 | } |
174 | 204 | ||
175 | let mut edits = usages | 205 | let mut edits = usages |
@@ -185,7 +215,7 @@ fn rename_to_self( | |||
185 | ), | 215 | ), |
186 | }); | 216 | }); |
187 | 217 | ||
188 | Some(RangeInfo::new(range, SourceChange::from(edits))) | 218 | Ok(RangeInfo::new(range, SourceChange::from(edits))) |
189 | } | 219 | } |
190 | 220 | ||
191 | fn text_edit_from_self_param( | 221 | fn text_edit_from_self_param( |
@@ -216,12 +246,13 @@ fn rename_self_to_param( | |||
216 | position: FilePosition, | 246 | position: FilePosition, |
217 | self_token: SyntaxToken, | 247 | self_token: SyntaxToken, |
218 | new_name: &str, | 248 | new_name: &str, |
219 | ) -> Option<RangeInfo<SourceChange>> { | 249 | ) -> Result<RangeInfo<SourceChange>, RenameError> { |
220 | let source_file = sema.parse(position.file_id); | 250 | let source_file = sema.parse(position.file_id); |
221 | let syn = source_file.syntax(); | 251 | let syn = source_file.syntax(); |
222 | 252 | ||
223 | let text = sema.db.file_text(position.file_id); | 253 | let text = sema.db.file_text(position.file_id); |
224 | let fn_def = find_node_at_offset::<ast::Fn>(syn, position.offset)?; | 254 | let fn_def = find_node_at_offset::<ast::Fn>(syn, position.offset) |
255 | .ok_or_else(|| RenameError("No surrounding method declaration found".to_string()))?; | ||
225 | let search_range = fn_def.syntax().text_range(); | 256 | let search_range = fn_def.syntax().text_range(); |
226 | 257 | ||
227 | let mut edits: Vec<SourceFileEdit> = vec![]; | 258 | let mut edits: Vec<SourceFileEdit> = vec![]; |
@@ -235,7 +266,8 @@ fn rename_self_to_param( | |||
235 | syn.token_at_offset(offset).find(|t| t.kind() == SyntaxKind::SELF_KW) | 266 | syn.token_at_offset(offset).find(|t| t.kind() == SyntaxKind::SELF_KW) |
236 | { | 267 | { |
237 | let edit = if let Some(ref self_param) = ast::SelfParam::cast(usage.parent()) { | 268 | let edit = if let Some(ref self_param) = ast::SelfParam::cast(usage.parent()) { |
238 | text_edit_from_self_param(syn, self_param, new_name)? | 269 | text_edit_from_self_param(syn, self_param, new_name) |
270 | .ok_or_else(|| RenameError("No target type found".to_string()))? | ||
239 | } else { | 271 | } else { |
240 | TextEdit::replace(usage.text_range(), String::from(new_name)) | 272 | TextEdit::replace(usage.text_range(), String::from(new_name)) |
241 | }; | 273 | }; |
@@ -246,15 +278,18 @@ fn rename_self_to_param( | |||
246 | let range = ast::SelfParam::cast(self_token.parent()) | 278 | let range = ast::SelfParam::cast(self_token.parent()) |
247 | .map_or(self_token.text_range(), |p| p.syntax().text_range()); | 279 | .map_or(self_token.text_range(), |p| p.syntax().text_range()); |
248 | 280 | ||
249 | Some(RangeInfo::new(range, SourceChange::from(edits))) | 281 | Ok(RangeInfo::new(range, SourceChange::from(edits))) |
250 | } | 282 | } |
251 | 283 | ||
252 | fn rename_reference( | 284 | fn rename_reference( |
253 | sema: &Semantics<RootDatabase>, | 285 | sema: &Semantics<RootDatabase>, |
254 | position: FilePosition, | 286 | position: FilePosition, |
255 | new_name: &str, | 287 | new_name: &str, |
256 | ) -> Option<RangeInfo<SourceChange>> { | 288 | ) -> Result<RangeInfo<SourceChange>, RenameError> { |
257 | let RangeInfo { range, info: refs } = find_all_refs(sema, position, None)?; | 289 | let RangeInfo { range, info: refs } = match find_all_refs(sema, position, None) { |
290 | Some(range_info) => range_info, | ||
291 | None => return Err(RenameError("No references found at position".to_string())), | ||
292 | }; | ||
258 | 293 | ||
259 | let edit = refs | 294 | let edit = refs |
260 | .into_iter() | 295 | .into_iter() |
@@ -262,10 +297,10 @@ fn rename_reference( | |||
262 | .collect::<Vec<_>>(); | 297 | .collect::<Vec<_>>(); |
263 | 298 | ||
264 | if edit.is_empty() { | 299 | if edit.is_empty() { |
265 | return None; | 300 | return Err(RenameError("No references found at position".to_string())); |
266 | } | 301 | } |
267 | 302 | ||
268 | Some(RangeInfo::new(range, SourceChange::from(edit))) | 303 | Ok(RangeInfo::new(range, SourceChange::from(edit))) |
269 | } | 304 | } |
270 | 305 | ||
271 | #[cfg(test)] | 306 | #[cfg(test)] |
@@ -280,25 +315,45 @@ mod tests { | |||
280 | fn check(new_name: &str, ra_fixture_before: &str, ra_fixture_after: &str) { | 315 | fn check(new_name: &str, ra_fixture_before: &str, ra_fixture_after: &str) { |
281 | let ra_fixture_after = &trim_indent(ra_fixture_after); | 316 | let ra_fixture_after = &trim_indent(ra_fixture_after); |
282 | let (analysis, position) = fixture::position(ra_fixture_before); | 317 | let (analysis, position) = fixture::position(ra_fixture_before); |
283 | let source_change = analysis.rename(position, new_name).unwrap(); | 318 | let rename_result = analysis |
284 | let mut text_edit_builder = TextEdit::builder(); | 319 | .rename(position, new_name) |
285 | let mut file_id: Option<FileId> = None; | 320 | .unwrap_or_else(|err| panic!("Rename to '{}' was cancelled: {}", new_name, err)); |
286 | if let Some(change) = source_change { | 321 | match rename_result { |
287 | for edit in change.info.source_file_edits { | 322 | Ok(source_change) => { |
288 | file_id = Some(edit.file_id); | 323 | let mut text_edit_builder = TextEdit::builder(); |
289 | for indel in edit.edit.into_iter() { | 324 | let mut file_id: Option<FileId> = None; |
290 | text_edit_builder.replace(indel.delete, indel.insert); | 325 | for edit in source_change.info.source_file_edits { |
326 | file_id = Some(edit.file_id); | ||
327 | for indel in edit.edit.into_iter() { | ||
328 | text_edit_builder.replace(indel.delete, indel.insert); | ||
329 | } | ||
291 | } | 330 | } |
331 | let mut result = analysis.file_text(file_id.unwrap()).unwrap().to_string(); | ||
332 | text_edit_builder.finish().apply(&mut result); | ||
333 | assert_eq_text!(ra_fixture_after, &*result); | ||
292 | } | 334 | } |
293 | } | 335 | Err(err) => { |
294 | let mut result = analysis.file_text(file_id.unwrap()).unwrap().to_string(); | 336 | if ra_fixture_after.starts_with("error:") { |
295 | text_edit_builder.finish().apply(&mut result); | 337 | let error_message = ra_fixture_after |
296 | assert_eq_text!(ra_fixture_after, &*result); | 338 | .chars() |
339 | .into_iter() | ||
340 | .skip("error:".len()) | ||
341 | .collect::<String>(); | ||
342 | assert_eq!(error_message.trim(), err.to_string()); | ||
343 | return; | ||
344 | } else { | ||
345 | panic!("Rename to '{}' failed unexpectedly: {}", new_name, err) | ||
346 | } | ||
347 | } | ||
348 | }; | ||
297 | } | 349 | } |
298 | 350 | ||
299 | fn check_expect(new_name: &str, ra_fixture: &str, expect: Expect) { | 351 | fn check_expect(new_name: &str, ra_fixture: &str, expect: Expect) { |
300 | let (analysis, position) = fixture::position(ra_fixture); | 352 | let (analysis, position) = fixture::position(ra_fixture); |
301 | let source_change = analysis.rename(position, new_name).unwrap().unwrap(); | 353 | let source_change = analysis |
354 | .rename(position, new_name) | ||
355 | .unwrap() | ||
356 | .expect("Expect returned RangeInfo to be Some, but was None"); | ||
302 | expect.assert_debug_eq(&source_change) | 357 | expect.assert_debug_eq(&source_change) |
303 | } | 358 | } |
304 | 359 | ||
@@ -313,11 +368,30 @@ mod tests { | |||
313 | } | 368 | } |
314 | 369 | ||
315 | #[test] | 370 | #[test] |
316 | fn test_rename_to_invalid_identifier() { | 371 | fn test_rename_to_invalid_identifier1() { |
317 | let (analysis, position) = fixture::position(r#"fn main() { let i<|> = 1; }"#); | 372 | check( |
318 | let new_name = "invalid!"; | 373 | "invalid!", |
319 | let source_change = analysis.rename(position, new_name).unwrap(); | 374 | r#"fn main() { let i<|> = 1; }"#, |
320 | assert!(source_change.is_none()); | 375 | "error: Invalid name `invalid!`: not an identifier", |
376 | ); | ||
377 | } | ||
378 | |||
379 | #[test] | ||
380 | fn test_rename_to_invalid_identifier2() { | ||
381 | check( | ||
382 | "multiple tokens", | ||
383 | r#"fn main() { let i<|> = 1; }"#, | ||
384 | "error: Invalid name `multiple tokens`: not an identifier", | ||
385 | ); | ||
386 | } | ||
387 | |||
388 | #[test] | ||
389 | fn test_rename_to_invalid_identifier3() { | ||
390 | check( | ||
391 | "let", | ||
392 | r#"fn main() { let i<|> = 1; }"#, | ||
393 | "error: Invalid name `let`: not an identifier", | ||
394 | ); | ||
321 | } | 395 | } |
322 | 396 | ||
323 | #[test] | 397 | #[test] |
@@ -350,6 +424,15 @@ fn main() { | |||
350 | } | 424 | } |
351 | 425 | ||
352 | #[test] | 426 | #[test] |
427 | fn test_rename_unresolved_reference() { | ||
428 | check( | ||
429 | "new_name", | ||
430 | r#"fn main() { let _ = unresolved_ref<|>; }"#, | ||
431 | "error: No references found at position", | ||
432 | ); | ||
433 | } | ||
434 | |||
435 | #[test] | ||
353 | fn test_rename_for_macro_args() { | 436 | fn test_rename_for_macro_args() { |
354 | check( | 437 | check( |
355 | "b", | 438 | "b", |
diff --git a/crates/ide_db/src/search.rs b/crates/ide_db/src/search.rs index edab1d644..8e3dcd99c 100644 --- a/crates/ide_db/src/search.rs +++ b/crates/ide_db/src/search.rs | |||
@@ -12,8 +12,9 @@ use once_cell::unsync::Lazy; | |||
12 | use rustc_hash::FxHashMap; | 12 | use rustc_hash::FxHashMap; |
13 | use syntax::{ast, match_ast, AstNode, TextRange, TextSize}; | 13 | use syntax::{ast, match_ast, AstNode, TextRange, TextSize}; |
14 | 14 | ||
15 | use crate::defs::NameClass; | ||
15 | use crate::{ | 16 | use crate::{ |
16 | defs::{classify_name_ref, Definition, NameRefClass}, | 17 | defs::{classify_name, classify_name_ref, Definition, NameRefClass}, |
17 | RootDatabase, | 18 | RootDatabase, |
18 | }; | 19 | }; |
19 | 20 | ||
@@ -226,9 +227,9 @@ impl<'a> FindUsages<'a> { | |||
226 | 227 | ||
227 | let search_scope = { | 228 | let search_scope = { |
228 | let base = self.def.search_scope(sema.db); | 229 | let base = self.def.search_scope(sema.db); |
229 | match self.scope { | 230 | match &self.scope { |
230 | None => base, | 231 | None => base, |
231 | Some(scope) => base.intersection(&scope), | 232 | Some(scope) => base.intersection(scope), |
232 | } | 233 | } |
233 | }; | 234 | }; |
234 | 235 | ||
@@ -251,54 +252,83 @@ impl<'a> FindUsages<'a> { | |||
251 | continue; | 252 | continue; |
252 | } | 253 | } |
253 | 254 | ||
254 | let name_ref: ast::NameRef = | 255 | match sema.find_node_at_offset_with_descend(&tree, offset) { |
255 | match sema.find_node_at_offset_with_descend(&tree, offset) { | 256 | Some(name_ref) => { |
256 | Some(it) => it, | 257 | if self.found_name_ref(&name_ref, sink) { |
257 | None => continue, | ||
258 | }; | ||
259 | |||
260 | match classify_name_ref(&sema, &name_ref) { | ||
261 | Some(NameRefClass::Definition(def)) if &def == self.def => { | ||
262 | let kind = if is_record_lit_name_ref(&name_ref) | ||
263 | || is_call_expr_name_ref(&name_ref) | ||
264 | { | ||
265 | ReferenceKind::StructLiteral | ||
266 | } else { | ||
267 | ReferenceKind::Other | ||
268 | }; | ||
269 | |||
270 | let reference = Reference { | ||
271 | file_range: sema.original_range(name_ref.syntax()), | ||
272 | kind, | ||
273 | access: reference_access(&def, &name_ref), | ||
274 | }; | ||
275 | if sink(reference) { | ||
276 | return; | 258 | return; |
277 | } | 259 | } |
278 | } | 260 | } |
279 | Some(NameRefClass::FieldShorthand { local, field }) => { | 261 | None => match sema.find_node_at_offset_with_descend(&tree, offset) { |
280 | let reference = match self.def { | 262 | Some(name) => { |
281 | Definition::Field(_) if &field == self.def => Reference { | 263 | if self.found_name(&name, sink) { |
282 | file_range: self.sema.original_range(name_ref.syntax()), | 264 | return; |
283 | kind: ReferenceKind::FieldShorthandForField, | 265 | } |
284 | access: reference_access(&field, &name_ref), | ||
285 | }, | ||
286 | Definition::Local(l) if &local == l => Reference { | ||
287 | file_range: self.sema.original_range(name_ref.syntax()), | ||
288 | kind: ReferenceKind::FieldShorthandForLocal, | ||
289 | access: reference_access(&Definition::Local(local), &name_ref), | ||
290 | }, | ||
291 | _ => continue, // not a usage | ||
292 | }; | ||
293 | if sink(reference) { | ||
294 | return; | ||
295 | } | 266 | } |
296 | } | 267 | None => {} |
297 | _ => {} // not a usage | 268 | }, |
298 | } | 269 | } |
299 | } | 270 | } |
300 | } | 271 | } |
301 | } | 272 | } |
273 | |||
274 | fn found_name_ref( | ||
275 | &self, | ||
276 | name_ref: &ast::NameRef, | ||
277 | sink: &mut dyn FnMut(Reference) -> bool, | ||
278 | ) -> bool { | ||
279 | match classify_name_ref(self.sema, &name_ref) { | ||
280 | Some(NameRefClass::Definition(def)) if &def == self.def => { | ||
281 | let kind = if is_record_lit_name_ref(&name_ref) || is_call_expr_name_ref(&name_ref) | ||
282 | { | ||
283 | ReferenceKind::StructLiteral | ||
284 | } else { | ||
285 | ReferenceKind::Other | ||
286 | }; | ||
287 | |||
288 | let reference = Reference { | ||
289 | file_range: self.sema.original_range(name_ref.syntax()), | ||
290 | kind, | ||
291 | access: reference_access(&def, &name_ref), | ||
292 | }; | ||
293 | sink(reference) | ||
294 | } | ||
295 | Some(NameRefClass::FieldShorthand { local, field }) => { | ||
296 | let reference = match self.def { | ||
297 | Definition::Field(_) if &field == self.def => Reference { | ||
298 | file_range: self.sema.original_range(name_ref.syntax()), | ||
299 | kind: ReferenceKind::FieldShorthandForField, | ||
300 | access: reference_access(&field, &name_ref), | ||
301 | }, | ||
302 | Definition::Local(l) if &local == l => Reference { | ||
303 | file_range: self.sema.original_range(name_ref.syntax()), | ||
304 | kind: ReferenceKind::FieldShorthandForLocal, | ||
305 | access: reference_access(&Definition::Local(local), &name_ref), | ||
306 | }, | ||
307 | _ => return false, // not a usage | ||
308 | }; | ||
309 | sink(reference) | ||
310 | } | ||
311 | _ => false, // not a usage | ||
312 | } | ||
313 | } | ||
314 | |||
315 | fn found_name(&self, name: &ast::Name, sink: &mut dyn FnMut(Reference) -> bool) -> bool { | ||
316 | match classify_name(self.sema, name) { | ||
317 | Some(NameClass::FieldShorthand { local: _, field }) => { | ||
318 | let reference = match self.def { | ||
319 | Definition::Field(_) if &field == self.def => Reference { | ||
320 | file_range: self.sema.original_range(name.syntax()), | ||
321 | kind: ReferenceKind::FieldShorthandForField, | ||
322 | // FIXME: mutable patterns should have `Write` access | ||
323 | access: Some(ReferenceAccess::Read), | ||
324 | }, | ||
325 | _ => return false, // not a usage | ||
326 | }; | ||
327 | sink(reference) | ||
328 | } | ||
329 | _ => false, // not a usage | ||
330 | } | ||
331 | } | ||
302 | } | 332 | } |
303 | 333 | ||
304 | fn reference_access(def: &Definition, name_ref: &ast::NameRef) -> Option<ReferenceAccess> { | 334 | fn reference_access(def: &Definition, name_ref: &ast::NameRef) -> Option<ReferenceAccess> { |
diff --git a/crates/proc_macro_srv/src/proc_macro/bridge/client.rs b/crates/proc_macro_srv/src/proc_macro/bridge/client.rs index cb4b3bdb0..55d6330cc 100644 --- a/crates/proc_macro_srv/src/proc_macro/bridge/client.rs +++ b/crates/proc_macro_srv/src/proc_macro/bridge/client.rs | |||
@@ -160,6 +160,7 @@ macro_rules! define_handles { | |||
160 | } | 160 | } |
161 | define_handles! { | 161 | define_handles! { |
162 | 'owned: | 162 | 'owned: |
163 | FreeFunctions, | ||
163 | TokenStream, | 164 | TokenStream, |
164 | TokenStreamBuilder, | 165 | TokenStreamBuilder, |
165 | TokenStreamIter, | 166 | TokenStreamIter, |
diff --git a/crates/proc_macro_srv/src/proc_macro/bridge/mod.rs b/crates/proc_macro_srv/src/proc_macro/bridge/mod.rs index aeb05aad4..b97886eb9 100644 --- a/crates/proc_macro_srv/src/proc_macro/bridge/mod.rs +++ b/crates/proc_macro_srv/src/proc_macro/bridge/mod.rs | |||
@@ -57,6 +57,10 @@ use std::thread; | |||
57 | macro_rules! with_api { | 57 | macro_rules! with_api { |
58 | ($S:ident, $self:ident, $m:ident) => { | 58 | ($S:ident, $self:ident, $m:ident) => { |
59 | $m! { | 59 | $m! { |
60 | FreeFunctions { | ||
61 | fn drop($self: $S::FreeFunctions); | ||
62 | fn track_env_var(var: &str, value: Option<&str>); | ||
63 | }, | ||
60 | TokenStream { | 64 | TokenStream { |
61 | fn drop($self: $S::TokenStream); | 65 | fn drop($self: $S::TokenStream); |
62 | fn clone($self: &$S::TokenStream) -> $S::TokenStream; | 66 | fn clone($self: &$S::TokenStream) -> $S::TokenStream; |
diff --git a/crates/proc_macro_srv/src/proc_macro/bridge/server.rs b/crates/proc_macro_srv/src/proc_macro/bridge/server.rs index 45d41ac02..3acb239af 100644 --- a/crates/proc_macro_srv/src/proc_macro/bridge/server.rs +++ b/crates/proc_macro_srv/src/proc_macro/bridge/server.rs | |||
@@ -11,6 +11,8 @@ use super::client::HandleStore; | |||
11 | /// Declare an associated item of one of the traits below, optionally | 11 | /// Declare an associated item of one of the traits below, optionally |
12 | /// adjusting it (i.e., adding bounds to types and default bodies to methods). | 12 | /// adjusting it (i.e., adding bounds to types and default bodies to methods). |
13 | macro_rules! associated_item { | 13 | macro_rules! associated_item { |
14 | (type FreeFunctions) => | ||
15 | (type FreeFunctions: 'static;); | ||
14 | (type TokenStream) => | 16 | (type TokenStream) => |
15 | (type TokenStream: 'static + Clone;); | 17 | (type TokenStream: 'static + Clone;); |
16 | (type TokenStreamBuilder) => | 18 | (type TokenStreamBuilder) => |
diff --git a/crates/proc_macro_srv/src/proc_macro/mod.rs b/crates/proc_macro_srv/src/proc_macro/mod.rs index ee0dc9722..fc6e7344f 100644 --- a/crates/proc_macro_srv/src/proc_macro/mod.rs +++ b/crates/proc_macro_srv/src/proc_macro/mod.rs | |||
@@ -924,3 +924,25 @@ impl fmt::Debug for Literal { | |||
924 | self.0.fmt(f) | 924 | self.0.fmt(f) |
925 | } | 925 | } |
926 | } | 926 | } |
927 | |||
928 | pub mod tracked_env { | ||
929 | use std::env::{self, VarError}; | ||
930 | use std::ffi::OsStr; | ||
931 | |||
932 | /// Retrieve an environment variable and add it to build dependency info. | ||
933 | /// Build system executing the compiler will know that the variable was accessed during | ||
934 | /// compilation, and will be able to rerun the build when the value of that variable changes. | ||
935 | /// Besides the dependency tracking this function should be equivalent to `env::var` from the | ||
936 | /// standard library, except that the argument must be UTF-8. | ||
937 | pub fn var<K: AsRef<OsStr> + AsRef<str>>(key: K) -> Result<String, VarError> { | ||
938 | use std::ops::Deref; | ||
939 | |||
940 | let key: &str = key.as_ref(); | ||
941 | let value = env::var(key); | ||
942 | super::bridge::client::FreeFunctions::track_env_var( | ||
943 | key, | ||
944 | value.as_ref().map(|t| t.deref()).ok(), | ||
945 | ); | ||
946 | value | ||
947 | } | ||
948 | } | ||
diff --git a/crates/proc_macro_srv/src/rustc_server.rs b/crates/proc_macro_srv/src/rustc_server.rs index 7d1695c86..c5fe3591e 100644 --- a/crates/proc_macro_srv/src/rustc_server.rs +++ b/crates/proc_macro_srv/src/rustc_server.rs | |||
@@ -242,6 +242,8 @@ impl TokenStreamBuilder { | |||
242 | } | 242 | } |
243 | } | 243 | } |
244 | 244 | ||
245 | pub struct FreeFunctions; | ||
246 | |||
245 | #[derive(Clone)] | 247 | #[derive(Clone)] |
246 | pub struct TokenStreamIter { | 248 | pub struct TokenStreamIter { |
247 | trees: IntoIter<TokenTree>, | 249 | trees: IntoIter<TokenTree>, |
@@ -254,6 +256,7 @@ pub struct Rustc { | |||
254 | } | 256 | } |
255 | 257 | ||
256 | impl server::Types for Rustc { | 258 | impl server::Types for Rustc { |
259 | type FreeFunctions = FreeFunctions; | ||
257 | type TokenStream = TokenStream; | 260 | type TokenStream = TokenStream; |
258 | type TokenStreamBuilder = TokenStreamBuilder; | 261 | type TokenStreamBuilder = TokenStreamBuilder; |
259 | type TokenStreamIter = TokenStreamIter; | 262 | type TokenStreamIter = TokenStreamIter; |
@@ -267,6 +270,13 @@ impl server::Types for Rustc { | |||
267 | type MultiSpan = Vec<Span>; | 270 | type MultiSpan = Vec<Span>; |
268 | } | 271 | } |
269 | 272 | ||
273 | impl server::FreeFunctions for Rustc { | ||
274 | fn track_env_var(&mut self, _var: &str, _value: Option<&str>) { | ||
275 | // FIXME: track env var accesses | ||
276 | // https://github.com/rust-lang/rust/pull/71858 | ||
277 | } | ||
278 | } | ||
279 | |||
270 | impl server::TokenStream for Rustc { | 280 | impl server::TokenStream for Rustc { |
271 | fn new(&mut self) -> Self::TokenStream { | 281 | fn new(&mut self) -> Self::TokenStream { |
272 | Self::TokenStream::new() | 282 | Self::TokenStream::new() |
diff --git a/crates/profile/Cargo.toml b/crates/profile/Cargo.toml index 261172d61..c5dfdff32 100644 --- a/crates/profile/Cargo.toml +++ b/crates/profile/Cargo.toml | |||
@@ -11,7 +11,7 @@ doctest = false | |||
11 | 11 | ||
12 | [dependencies] | 12 | [dependencies] |
13 | once_cell = "1.3.1" | 13 | once_cell = "1.3.1" |
14 | cfg-if = "0.1.10" | 14 | cfg-if = "1" |
15 | libc = "0.2.73" | 15 | libc = "0.2.73" |
16 | backtrace = { version = "0.3.44", optional = true } | 16 | backtrace = { version = "0.3.44", optional = true } |
17 | 17 | ||
diff --git a/crates/project_model/src/sysroot.rs b/crates/project_model/src/sysroot.rs index 871808d89..e529e07b0 100644 --- a/crates/project_model/src/sysroot.rs +++ b/crates/project_model/src/sysroot.rs | |||
@@ -90,9 +90,15 @@ impl Sysroot { | |||
90 | } | 90 | } |
91 | 91 | ||
92 | if sysroot.by_name("core").is_none() { | 92 | if sysroot.by_name("core").is_none() { |
93 | let var_note = if env::var_os("RUST_SRC_PATH").is_some() { | ||
94 | " (`RUST_SRC_PATH` might be incorrect, try unsetting it)" | ||
95 | } else { | ||
96 | "" | ||
97 | }; | ||
93 | anyhow::bail!( | 98 | anyhow::bail!( |
94 | "could not find libcore in sysroot path `{}`", | 99 | "could not find libcore in sysroot path `{}`{}", |
95 | sysroot_src_dir.as_ref().display() | 100 | sysroot_src_dir.as_ref().display(), |
101 | var_note, | ||
96 | ); | 102 | ); |
97 | } | 103 | } |
98 | 104 | ||
diff --git a/crates/rust-analyzer/src/handlers.rs b/crates/rust-analyzer/src/handlers.rs index ba73abcac..215be850f 100644 --- a/crates/rust-analyzer/src/handlers.rs +++ b/crates/rust-analyzer/src/handlers.rs | |||
@@ -646,14 +646,9 @@ pub(crate) fn handle_prepare_rename( | |||
646 | let _p = profile::span("handle_prepare_rename"); | 646 | let _p = profile::span("handle_prepare_rename"); |
647 | let position = from_proto::file_position(&snap, params)?; | 647 | let position = from_proto::file_position(&snap, params)?; |
648 | 648 | ||
649 | let optional_change = snap.analysis.rename(position, "dummy")?; | 649 | let change = snap.analysis.rename(position, "dummy")??; |
650 | let range = match optional_change { | ||
651 | None => return Ok(None), | ||
652 | Some(it) => it.range, | ||
653 | }; | ||
654 | |||
655 | let line_index = snap.analysis.file_line_index(position.file_id)?; | 650 | let line_index = snap.analysis.file_line_index(position.file_id)?; |
656 | let range = to_proto::range(&line_index, range); | 651 | let range = to_proto::range(&line_index, change.range); |
657 | Ok(Some(PrepareRenameResponse::Range(range))) | 652 | Ok(Some(PrepareRenameResponse::Range(range))) |
658 | } | 653 | } |
659 | 654 | ||
@@ -672,12 +667,8 @@ pub(crate) fn handle_rename( | |||
672 | .into()); | 667 | .into()); |
673 | } | 668 | } |
674 | 669 | ||
675 | let optional_change = snap.analysis.rename(position, &*params.new_name)?; | 670 | let change = snap.analysis.rename(position, &*params.new_name)??; |
676 | let source_change = match optional_change { | 671 | let workspace_edit = to_proto::workspace_edit(&snap, change.info)?; |
677 | None => return Ok(None), | ||
678 | Some(it) => it.info, | ||
679 | }; | ||
680 | let workspace_edit = to_proto::workspace_edit(&snap, source_change)?; | ||
681 | Ok(Some(workspace_edit)) | 672 | Ok(Some(workspace_edit)) |
682 | } | 673 | } |
683 | 674 | ||
diff --git a/crates/syntax/Cargo.toml b/crates/syntax/Cargo.toml index 0b15f10e9..547fe9f47 100644 --- a/crates/syntax/Cargo.toml +++ b/crates/syntax/Cargo.toml | |||
@@ -13,7 +13,7 @@ doctest = false | |||
13 | [dependencies] | 13 | [dependencies] |
14 | itertools = "0.9.0" | 14 | itertools = "0.9.0" |
15 | rowan = "0.10.0" | 15 | rowan = "0.10.0" |
16 | rustc_lexer = { version = "681.0.0", package = "rustc-ap-rustc_lexer" } | 16 | rustc_lexer = { version = "682.0.0", package = "rustc-ap-rustc_lexer" } |
17 | rustc-hash = "1.1.0" | 17 | rustc-hash = "1.1.0" |
18 | arrayvec = "0.5.1" | 18 | arrayvec = "0.5.1" |
19 | once_cell = "1.3.1" | 19 | once_cell = "1.3.1" |