From 3e3fd4aabeb7b71ae634677413e38f7acfb2d724 Mon Sep 17 00:00:00 2001 From: Giga Bowser <45986823+Giga-Bowser@users.noreply.github.com> Date: Fri, 1 Nov 2024 12:35:01 -0400 Subject: [PATCH 01/17] Use snippet placeholders for generated match arms --- .../src/handlers/add_missing_match_arms.rs | 218 +++++++++--------- .../crates/ide-assists/src/tests/generated.rs | 4 +- 2 files changed, 114 insertions(+), 108 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs index a211ca8f2d675..71756def14562 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs @@ -30,8 +30,8 @@ use crate::{utils, AssistContext, AssistId, AssistKind, Assists}; // // fn handle(action: Action) { // match action { -// $0Action::Move { distance } => todo!(), -// Action::Stop => todo!(), +// Action::Move { distance } => ${1:todo!()}, +// Action::Stop => ${0:todo!()}, // } // } // ``` @@ -234,8 +234,10 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>) } } + let mut todo_placeholders = Vec::new(); let mut first_new_arm = None; for arm in missing_arms { + todo_placeholders.push(arm.expr().unwrap()); first_new_arm.get_or_insert_with(|| arm.clone()); new_match_arm_list.add_arm(arm); } @@ -248,14 +250,18 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>) make::ext::expr_todo(), ) .clone_for_update(); + todo_placeholders.push(arm.expr().unwrap()); first_new_arm.get_or_insert_with(|| arm.clone()); new_match_arm_list.add_arm(arm); } if let (Some(first_new_arm), Some(cap)) = (first_new_arm, ctx.config.snippet_cap) { - match first_new_arm.syntax().descendants().find_map(ast::WildcardPat::cast) { - Some(it) => edit.add_placeholder_snippet(cap, it), - None => edit.add_tabstop_before(cap, first_new_arm), + if let Some(it) = first_new_arm.syntax().descendants().find_map(ast::WildcardPat::cast) { + edit.add_placeholder_snippet(cap, it); + } + + for placeholder in todo_placeholders { + edit.add_placeholder_snippet(cap, placeholder); } } @@ -581,8 +587,8 @@ fn foo(a: bool) { r#" fn foo(a: bool) { match a { - $0true => todo!(), - false => todo!(), + true => ${1:todo!()}, + false => ${0:todo!()}, } } "#, @@ -604,7 +610,7 @@ fn foo(a: bool) { fn foo(a: bool) { match a { true => {} - $0false => todo!(), + false => ${0:todo!()}, } } "#, @@ -654,10 +660,10 @@ fn foo(a: bool) { r#" fn foo(a: bool) { match (a, a) { - $0(true, true) => todo!(), - (true, false) => todo!(), - (false, true) => todo!(), - (false, false) => todo!(), + (true, true) => ${1:todo!()}, + (true, false) => ${2:todo!()}, + (false, true) => ${3:todo!()}, + (false, false) => ${0:todo!()}, } } "#, @@ -677,8 +683,8 @@ fn foo(a: bool) { r#" fn foo(a: bool) { match [a] { - $0[true] => todo!(), - [false] => todo!(), + [true] => ${1:todo!()}, + [false] => ${0:todo!()}, } } "#, @@ -695,8 +701,8 @@ fn foo(a: bool) { r#" fn foo(a: bool) { match [a,] { - $0[true] => todo!(), - [false] => todo!(), + [true] => ${1:todo!()}, + [false] => ${0:todo!()}, } } "#, @@ -715,9 +721,9 @@ fn foo(a: bool) { fn foo(a: bool) { match [a, a] { [true, true] => todo!(), - $0[true, false] => todo!(), - [false, true] => todo!(), - [false, false] => todo!(), + [true, false] => ${1:todo!()}, + [false, true] => ${2:todo!()}, + [false, false] => ${0:todo!()}, } } "#, @@ -734,10 +740,10 @@ fn foo(a: bool) { r#" fn foo(a: bool) { match [a, a] { - $0[true, true] => todo!(), - [true, false] => todo!(), - [false, true] => todo!(), - [false, false] => todo!(), + [true, true] => ${1:todo!()}, + [true, false] => ${2:todo!()}, + [false, true] => ${3:todo!()}, + [false, false] => ${0:todo!()}, } } "#, @@ -759,8 +765,8 @@ fn foo(a: bool) { fn foo(a: bool) { match (a, a) { (true | false, true) => {} - $0(true, false) => todo!(), - (false, false) => todo!(), + (true, false) => ${1:todo!()}, + (false, false) => ${0:todo!()}, } } "#, @@ -779,9 +785,9 @@ fn foo(a: bool) { fn foo(a: bool) { match (a, a) { (false, true) => {} - $0(true, true) => todo!(), - (true, false) => todo!(), - (false, false) => todo!(), + (true, true) => ${1:todo!()}, + (true, false) => ${2:todo!()}, + (false, false) => ${0:todo!()}, } } "#, @@ -815,7 +821,7 @@ fn main() { match A::As { A::Bs { x, y: Some(_) } => {} A::Cs(_, Some(_)) => {} - $0A::As => todo!(), + A::As => ${0:todo!()}, } } "#, @@ -838,7 +844,7 @@ fn main() { fn main() { match None { None => {} - Some(${0:_}) => todo!(), + Some(${1:_}) => ${0:todo!()}, } } "#, @@ -862,7 +868,7 @@ enum A { As, Bs, Cs(Option) } fn main() { match A::As { A::Cs(_) | A::Bs => {} - $0A::As => todo!(), + A::As => ${0:todo!()}, } } "#, @@ -892,8 +898,8 @@ fn main() { A::Bs if 0 < 1 => {} A::Ds(_value) => { let x = 1; } A::Es(B::Xs) => (), - $0A::As => todo!(), - A::Cs => todo!(), + A::As => ${1:todo!()}, + A::Cs => ${0:todo!()}, } } "#, @@ -919,7 +925,7 @@ fn main() { match A::As { A::As(_) => {} a @ A::Bs(_) => {} - A::Cs(${0:_}) => todo!(), + A::Cs(${1:_}) => ${0:todo!()}, } } "#, @@ -945,11 +951,11 @@ enum A { As, Bs, Cs(String), Ds(String, String), Es { x: usize, y: usize } } fn main() { let a = A::As; match a { - $0A::As => todo!(), - A::Bs => todo!(), - A::Cs(_) => todo!(), - A::Ds(_, _) => todo!(), - A::Es { x, y } => todo!(), + A::As => ${1:todo!()}, + A::Bs => ${2:todo!()}, + A::Cs(_) => ${3:todo!()}, + A::Ds(_, _) => ${4:todo!()}, + A::Es { x, y } => ${0:todo!()}, } } "#, @@ -982,9 +988,9 @@ fn main() { let b = B::One; match (a, b) { (A::Two, B::One) => {}, - $0(A::One, B::One) => todo!(), - (A::One, B::Two) => todo!(), - (A::Two, B::Two) => todo!(), + (A::One, B::One) => ${1:todo!()}, + (A::One, B::Two) => ${2:todo!()}, + (A::Two, B::Two) => ${0:todo!()}, } } "#, @@ -1013,10 +1019,10 @@ fn main() { let a = A::One; let b = B::One; match (a, b) { - $0(A::One, B::One) => todo!(), - (A::One, B::Two) => todo!(), - (A::Two, B::One) => todo!(), - (A::Two, B::Two) => todo!(), + (A::One, B::One) => ${1:todo!()}, + (A::One, B::Two) => ${2:todo!()}, + (A::Two, B::One) => ${3:todo!()}, + (A::Two, B::Two) => ${0:todo!()}, } } "#, @@ -1045,10 +1051,10 @@ fn main() { let a = A::One; let b = B::One; match (&a, &b) { - $0(A::One, B::One) => todo!(), - (A::One, B::Two) => todo!(), - (A::Two, B::One) => todo!(), - (A::Two, B::Two) => todo!(), + (A::One, B::One) => ${1:todo!()}, + (A::One, B::Two) => ${2:todo!()}, + (A::Two, B::One) => ${3:todo!()}, + (A::Two, B::Two) => ${0:todo!()}, } } "#, @@ -1080,9 +1086,9 @@ fn main() { let b = B::One; match (a, b) { (A::Two, B::One) => {} - $0(A::One, B::One) => todo!(), - (A::One, B::Two) => todo!(), - (A::Two, B::Two) => todo!(), + (A::One, B::One) => ${1:todo!()}, + (A::One, B::Two) => ${2:todo!()}, + (A::Two, B::Two) => ${0:todo!()}, } } "#, @@ -1107,9 +1113,9 @@ fn main() { match (A, B, C) { (A | B , A, A | B | C) => (), (A | B | C , B | C, A | B | C) => (), - $0(C, A, A) => todo!(), - (C, A, B) => todo!(), - (C, A, C) => todo!(), + (C, A, A) => ${1:todo!()}, + (C, A, B) => ${2:todo!()}, + (C, A, C) => ${0:todo!()}, } } "#, @@ -1138,7 +1144,7 @@ fn main() { match (a, b) { (Some(_), _) => {} (None, Some(_)) => {} - $0(None, None) => todo!(), + (None, None) => ${0:todo!()}, } } "#, @@ -1203,8 +1209,8 @@ enum A { One, Two } fn main() { let a = A::One; match (a, ) { - $0(A::One,) => todo!(), - (A::Two,) => todo!(), + (A::One,) => ${1:todo!()}, + (A::Two,) => ${0:todo!()}, } } "#, @@ -1228,7 +1234,7 @@ enum A { As } fn foo(a: &A) { match a { - $0A::As => todo!(), + A::As => ${0:todo!()}, } } "#, @@ -1253,7 +1259,7 @@ enum A { fn foo(a: &mut A) { match a { - $0A::Es { x, y } => todo!(), + A::Es { x, y } => ${0:todo!()}, } } "#, @@ -1313,8 +1319,8 @@ enum E { X, Y } fn main() { match E::X { - $0E::X => todo!(), - E::Y => todo!(), + E::X => ${1:todo!()}, + E::Y => ${0:todo!()}, } } "#, @@ -1360,8 +1366,8 @@ use foo::E::X; fn main() { match X { - $0X => todo!(), - foo::E::Y => todo!(), + X => ${1:todo!()}, + foo::E::Y => ${0:todo!()}, } } "#, @@ -1388,7 +1394,7 @@ fn foo(a: A) { match a { // foo bar baz A::One => {} - $0A::Two => todo!(), + A::Two => ${0:todo!()}, // This is where the rest should be } } @@ -1412,8 +1418,8 @@ fn foo(a: A) { enum A { One, Two } fn foo(a: A) { match a { - $0A::One => todo!(), - A::Two => todo!(), + A::One => ${1:todo!()}, + A::Two => ${0:todo!()}, // foo bar baz } } @@ -1437,8 +1443,8 @@ fn foo(a: A) { enum A { One, Two, } fn foo(a: A) { match a { - $0A::One => todo!(), - A::Two => todo!(), + A::One => ${1:todo!()}, + A::Two => ${0:todo!()}, } } "#, @@ -1460,8 +1466,8 @@ fn foo(opt: Option) { r#" fn foo(opt: Option) { match opt { - Some(${0:_}) => todo!(), - None => todo!(), + Some(${1:_}) => ${2:todo!()}, + None => ${0:todo!()}, } } "#, @@ -1493,9 +1499,9 @@ enum Test { fn foo(t: Test) { m!(match t { - $0Test::A => todo!(), - Test::B => todo!(), - Test::C => todo!(), + Test::A => ${1:todo!()}, + Test::B => ${2:todo!()}, + Test::C => ${0:todo!()}, }); }"#, ); @@ -1530,7 +1536,7 @@ fn foo(t: bool) { fn foo(t: bool) { match t { true => 1 + 2, - $0false => todo!(), + false => ${0:todo!()}, } }"#, ); @@ -1550,7 +1556,7 @@ fn foo(t: bool) { fn foo(t: bool) { match t { true => 1 + 2, - $0false => todo!(), + false => ${0:todo!()}, } }"#, ); @@ -1571,8 +1577,8 @@ fn foo(t: bool) { fn foo(t: bool) { match t { _ => 1 + 2, - $0true => todo!(), - false => todo!(), + true => ${1:todo!()}, + false => ${0:todo!()}, } }"#, ); @@ -1595,8 +1601,8 @@ pub enum E { A, #[doc(hidden)] B, } r#" fn foo(t: ::e::E) { match t { - $0e::E::A => todo!(), - _ => todo!(), + e::E::A => ${1:todo!()}, + _ => ${0:todo!()}, } } "#, @@ -1620,9 +1626,9 @@ pub enum E { A, #[doc(hidden)] B, } r#" fn foo(t: (bool, ::e::E)) { match t { - $0(true, e::E::A) => todo!(), - (false, e::E::A) => todo!(), - _ => todo!(), + (true, e::E::A) => ${1:todo!()}, + (false, e::E::A) => ${2:todo!()}, + _ => ${0:todo!()}, } } "#, @@ -1646,7 +1652,7 @@ pub enum E { #[doc(hidden)] A, } r#" fn foo(t: ::e::E) { match t { - ${0:_} => todo!(), + ${1:_} => ${0:todo!()}, } } "#, @@ -1707,7 +1713,7 @@ pub enum E { A, } fn foo(t: ::e::E) { match t { e::E::A => todo!(), - ${0:_} => todo!(), + ${1:_} => ${0:todo!()}, } } "#, @@ -1732,8 +1738,8 @@ pub enum E { A, } r#" fn foo(t: ::e::E) { match t { - $0e::E::A => todo!(), - _ => todo!(), + e::E::A => ${1:todo!()}, + _ => ${0:todo!()}, } } "#, @@ -1757,8 +1763,8 @@ pub enum E { A, #[doc(hidden)] B }"#, r#" fn foo(t: ::e::E) { match t { - $0e::E::A => todo!(), - _ => todo!(), + e::E::A => ${1:todo!()}, + _ => ${0:todo!()}, } } "#, @@ -1784,7 +1790,7 @@ pub enum E { A, #[doc(hidden)] B }"#, fn foo(t: ::e::E) { match t { e::E::A => todo!(), - ${0:_} => todo!(), + ${1:_} => ${0:todo!()}, } } "#, @@ -1809,7 +1815,7 @@ pub enum E { #[doc(hidden)] A, }"#, fn foo(t: ::e::E, b: bool) { match t { _ if b => todo!(), - ${0:_} => todo!(), + ${1:_} => ${0:todo!()}, } } "#, @@ -1850,8 +1856,8 @@ pub enum E { A, #[doc(hidden)] B, }"#, r#" fn foo(t: ::e::E) { match t { - $0e::E::A => todo!(), - _ => todo!(), + e::E::A => ${1:todo!()}, + _ => ${0:todo!()}, } } "#, @@ -1874,8 +1880,8 @@ enum E { A, #[doc(hidden)] B, } fn foo(t: E) { match t { - $0E::A => todo!(), - E::B => todo!(), + E::A => ${1:todo!()}, + E::B => ${0:todo!()}, } }"#, ); @@ -1899,8 +1905,8 @@ enum E { A, B, } fn foo(t: E) { match t { - $0E::A => todo!(), - E::B => todo!(), + E::A => ${1:todo!()}, + E::B => ${0:todo!()}, } }"#, ); @@ -1924,8 +1930,8 @@ enum E { A, #[doc(hidden)] B, } fn foo(t: E) { match t { - $0E::A => todo!(), - E::B => todo!(), + E::A => ${1:todo!()}, + E::B => ${0:todo!()}, } }"#, ); @@ -1975,8 +1981,8 @@ enum A { fn a() { let b = A::A; match b { - $0A::A => todo!(), - A::Missing { a, u32, c } => todo!(), + A::A => ${1:todo!()}, + A::Missing { a, u32, c } => ${0:todo!()}, } }"#, ) @@ -2013,8 +2019,8 @@ pub enum E { fn f() { let value = E::A; match value { - $0E::A => todo!(), - E::B(s) => todo!(), + E::A => ${1:todo!()}, + E::B(s) => ${0:todo!()}, } } "#, @@ -2051,8 +2057,8 @@ pub enum E { fn f() { let value = E::A; match value { - $0E::A => todo!(), - E::B(s1, s2) => todo!(), + E::A => ${1:todo!()}, + E::B(s1, s2) => ${0:todo!()}, } } "#, diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs b/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs index 64b7ab1a12301..8fffe7713f95b 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs @@ -187,8 +187,8 @@ enum Action { Move { distance: u32 }, Stop } fn handle(action: Action) { match action { - $0Action::Move { distance } => todo!(), - Action::Stop => todo!(), + Action::Move { distance } => ${1:todo!()}, + Action::Stop => ${0:todo!()}, } } "#####, From bbfee6010464618aa381380c7f4e4013449c6910 Mon Sep 17 00:00:00 2001 From: Giga Bowser <45986823+Giga-Bowser@users.noreply.github.com> Date: Tue, 5 Nov 2024 12:13:42 -0500 Subject: [PATCH 02/17] Properly use final tabstop when adding missing match arms --- .../src/handlers/add_missing_match_arms.rs | 121 ++++++++++-------- .../crates/ide-assists/src/tests/generated.rs | 2 +- 2 files changed, 66 insertions(+), 57 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs index 71756def14562..236d33878edc1 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs @@ -31,7 +31,7 @@ use crate::{utils, AssistContext, AssistId, AssistKind, Assists}; // fn handle(action: Action) { // match action { // Action::Move { distance } => ${1:todo!()}, -// Action::Stop => ${0:todo!()}, +// Action::Stop => ${2:todo!()},$0 // } // } // ``` @@ -234,12 +234,11 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>) } } + let mut added_arms = Vec::new(); let mut todo_placeholders = Vec::new(); - let mut first_new_arm = None; for arm in missing_arms { todo_placeholders.push(arm.expr().unwrap()); - first_new_arm.get_or_insert_with(|| arm.clone()); - new_match_arm_list.add_arm(arm); + added_arms.push(arm); } if needs_catch_all_arm && !has_catch_all_arm { @@ -251,18 +250,28 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>) ) .clone_for_update(); todo_placeholders.push(arm.expr().unwrap()); - first_new_arm.get_or_insert_with(|| arm.clone()); + added_arms.push(arm); + } + + let first_new_arm = added_arms.first().cloned(); + let last_new_arm = added_arms.last().cloned(); + + for arm in added_arms { new_match_arm_list.add_arm(arm); } - if let (Some(first_new_arm), Some(cap)) = (first_new_arm, ctx.config.snippet_cap) { - if let Some(it) = first_new_arm.syntax().descendants().find_map(ast::WildcardPat::cast) { + if let Some(cap) = ctx.config.snippet_cap { + if let Some(it) = first_new_arm.and_then(|arm| arm.syntax().descendants().find_map(ast::WildcardPat::cast)) { edit.add_placeholder_snippet(cap, it); } for placeholder in todo_placeholders { edit.add_placeholder_snippet(cap, placeholder); } + + if let Some(arm) = last_new_arm { + edit.add_tabstop_after(cap, arm); + } } // FIXME: Hack for mutable syntax trees not having great support for macros @@ -588,7 +597,7 @@ fn foo(a: bool) { fn foo(a: bool) { match a { true => ${1:todo!()}, - false => ${0:todo!()}, + false => ${2:todo!()},$0 } } "#, @@ -610,7 +619,7 @@ fn foo(a: bool) { fn foo(a: bool) { match a { true => {} - false => ${0:todo!()}, + false => ${1:todo!()},$0 } } "#, @@ -663,7 +672,7 @@ fn foo(a: bool) { (true, true) => ${1:todo!()}, (true, false) => ${2:todo!()}, (false, true) => ${3:todo!()}, - (false, false) => ${0:todo!()}, + (false, false) => ${4:todo!()},$0 } } "#, @@ -684,7 +693,7 @@ fn foo(a: bool) { fn foo(a: bool) { match [a] { [true] => ${1:todo!()}, - [false] => ${0:todo!()}, + [false] => ${2:todo!()},$0 } } "#, @@ -702,7 +711,7 @@ fn foo(a: bool) { fn foo(a: bool) { match [a,] { [true] => ${1:todo!()}, - [false] => ${0:todo!()}, + [false] => ${2:todo!()},$0 } } "#, @@ -723,7 +732,7 @@ fn foo(a: bool) { [true, true] => todo!(), [true, false] => ${1:todo!()}, [false, true] => ${2:todo!()}, - [false, false] => ${0:todo!()}, + [false, false] => ${3:todo!()},$0 } } "#, @@ -743,7 +752,7 @@ fn foo(a: bool) { [true, true] => ${1:todo!()}, [true, false] => ${2:todo!()}, [false, true] => ${3:todo!()}, - [false, false] => ${0:todo!()}, + [false, false] => ${4:todo!()},$0 } } "#, @@ -766,7 +775,7 @@ fn foo(a: bool) { match (a, a) { (true | false, true) => {} (true, false) => ${1:todo!()}, - (false, false) => ${0:todo!()}, + (false, false) => ${2:todo!()},$0 } } "#, @@ -787,7 +796,7 @@ fn foo(a: bool) { (false, true) => {} (true, true) => ${1:todo!()}, (true, false) => ${2:todo!()}, - (false, false) => ${0:todo!()}, + (false, false) => ${3:todo!()},$0 } } "#, @@ -821,7 +830,7 @@ fn main() { match A::As { A::Bs { x, y: Some(_) } => {} A::Cs(_, Some(_)) => {} - A::As => ${0:todo!()}, + A::As => ${1:todo!()},$0 } } "#, @@ -844,7 +853,7 @@ fn main() { fn main() { match None { None => {} - Some(${1:_}) => ${0:todo!()}, + Some(${1:_}) => ${2:todo!()},$0 } } "#, @@ -868,7 +877,7 @@ enum A { As, Bs, Cs(Option) } fn main() { match A::As { A::Cs(_) | A::Bs => {} - A::As => ${0:todo!()}, + A::As => ${1:todo!()},$0 } } "#, @@ -899,7 +908,7 @@ fn main() { A::Ds(_value) => { let x = 1; } A::Es(B::Xs) => (), A::As => ${1:todo!()}, - A::Cs => ${0:todo!()}, + A::Cs => ${2:todo!()},$0 } } "#, @@ -925,7 +934,7 @@ fn main() { match A::As { A::As(_) => {} a @ A::Bs(_) => {} - A::Cs(${1:_}) => ${0:todo!()}, + A::Cs(${1:_}) => ${2:todo!()},$0 } } "#, @@ -955,7 +964,7 @@ fn main() { A::Bs => ${2:todo!()}, A::Cs(_) => ${3:todo!()}, A::Ds(_, _) => ${4:todo!()}, - A::Es { x, y } => ${0:todo!()}, + A::Es { x, y } => ${5:todo!()},$0 } } "#, @@ -990,7 +999,7 @@ fn main() { (A::Two, B::One) => {}, (A::One, B::One) => ${1:todo!()}, (A::One, B::Two) => ${2:todo!()}, - (A::Two, B::Two) => ${0:todo!()}, + (A::Two, B::Two) => ${3:todo!()},$0 } } "#, @@ -1022,7 +1031,7 @@ fn main() { (A::One, B::One) => ${1:todo!()}, (A::One, B::Two) => ${2:todo!()}, (A::Two, B::One) => ${3:todo!()}, - (A::Two, B::Two) => ${0:todo!()}, + (A::Two, B::Two) => ${4:todo!()},$0 } } "#, @@ -1054,7 +1063,7 @@ fn main() { (A::One, B::One) => ${1:todo!()}, (A::One, B::Two) => ${2:todo!()}, (A::Two, B::One) => ${3:todo!()}, - (A::Two, B::Two) => ${0:todo!()}, + (A::Two, B::Two) => ${4:todo!()},$0 } } "#, @@ -1088,7 +1097,7 @@ fn main() { (A::Two, B::One) => {} (A::One, B::One) => ${1:todo!()}, (A::One, B::Two) => ${2:todo!()}, - (A::Two, B::Two) => ${0:todo!()}, + (A::Two, B::Two) => ${3:todo!()},$0 } } "#, @@ -1115,7 +1124,7 @@ fn main() { (A | B | C , B | C, A | B | C) => (), (C, A, A) => ${1:todo!()}, (C, A, B) => ${2:todo!()}, - (C, A, C) => ${0:todo!()}, + (C, A, C) => ${3:todo!()},$0 } } "#, @@ -1144,7 +1153,7 @@ fn main() { match (a, b) { (Some(_), _) => {} (None, Some(_)) => {} - (None, None) => ${0:todo!()}, + (None, None) => ${1:todo!()},$0 } } "#, @@ -1210,7 +1219,7 @@ fn main() { let a = A::One; match (a, ) { (A::One,) => ${1:todo!()}, - (A::Two,) => ${0:todo!()}, + (A::Two,) => ${2:todo!()},$0 } } "#, @@ -1234,7 +1243,7 @@ enum A { As } fn foo(a: &A) { match a { - A::As => ${0:todo!()}, + A::As => ${1:todo!()},$0 } } "#, @@ -1259,7 +1268,7 @@ enum A { fn foo(a: &mut A) { match a { - A::Es { x, y } => ${0:todo!()}, + A::Es { x, y } => ${1:todo!()},$0 } } "#, @@ -1320,7 +1329,7 @@ enum E { X, Y } fn main() { match E::X { E::X => ${1:todo!()}, - E::Y => ${0:todo!()}, + E::Y => ${2:todo!()},$0 } } "#, @@ -1367,7 +1376,7 @@ use foo::E::X; fn main() { match X { X => ${1:todo!()}, - foo::E::Y => ${0:todo!()}, + foo::E::Y => ${2:todo!()},$0 } } "#, @@ -1394,7 +1403,7 @@ fn foo(a: A) { match a { // foo bar baz A::One => {} - A::Two => ${0:todo!()}, + A::Two => ${1:todo!()},$0 // This is where the rest should be } } @@ -1419,7 +1428,7 @@ enum A { One, Two } fn foo(a: A) { match a { A::One => ${1:todo!()}, - A::Two => ${0:todo!()}, + A::Two => ${2:todo!()},$0 // foo bar baz } } @@ -1444,7 +1453,7 @@ enum A { One, Two, } fn foo(a: A) { match a { A::One => ${1:todo!()}, - A::Two => ${0:todo!()}, + A::Two => ${2:todo!()},$0 } } "#, @@ -1467,7 +1476,7 @@ fn foo(opt: Option) { fn foo(opt: Option) { match opt { Some(${1:_}) => ${2:todo!()}, - None => ${0:todo!()}, + None => ${3:todo!()},$0 } } "#, @@ -1501,7 +1510,7 @@ fn foo(t: Test) { m!(match t { Test::A => ${1:todo!()}, Test::B => ${2:todo!()}, - Test::C => ${0:todo!()}, + Test::C => ${3:todo!()},$0 }); }"#, ); @@ -1536,7 +1545,7 @@ fn foo(t: bool) { fn foo(t: bool) { match t { true => 1 + 2, - false => ${0:todo!()}, + false => ${1:todo!()},$0 } }"#, ); @@ -1556,7 +1565,7 @@ fn foo(t: bool) { fn foo(t: bool) { match t { true => 1 + 2, - false => ${0:todo!()}, + false => ${1:todo!()},$0 } }"#, ); @@ -1578,7 +1587,7 @@ fn foo(t: bool) { match t { _ => 1 + 2, true => ${1:todo!()}, - false => ${0:todo!()}, + false => ${2:todo!()},$0 } }"#, ); @@ -1602,7 +1611,7 @@ pub enum E { A, #[doc(hidden)] B, } fn foo(t: ::e::E) { match t { e::E::A => ${1:todo!()}, - _ => ${0:todo!()}, + _ => ${2:todo!()},$0 } } "#, @@ -1628,7 +1637,7 @@ fn foo(t: (bool, ::e::E)) { match t { (true, e::E::A) => ${1:todo!()}, (false, e::E::A) => ${2:todo!()}, - _ => ${0:todo!()}, + _ => ${3:todo!()},$0 } } "#, @@ -1652,7 +1661,7 @@ pub enum E { #[doc(hidden)] A, } r#" fn foo(t: ::e::E) { match t { - ${1:_} => ${0:todo!()}, + ${1:_} => ${2:todo!()},$0 } } "#, @@ -1713,7 +1722,7 @@ pub enum E { A, } fn foo(t: ::e::E) { match t { e::E::A => todo!(), - ${1:_} => ${0:todo!()}, + ${1:_} => ${2:todo!()},$0 } } "#, @@ -1739,7 +1748,7 @@ pub enum E { A, } fn foo(t: ::e::E) { match t { e::E::A => ${1:todo!()}, - _ => ${0:todo!()}, + _ => ${2:todo!()},$0 } } "#, @@ -1764,7 +1773,7 @@ pub enum E { A, #[doc(hidden)] B }"#, fn foo(t: ::e::E) { match t { e::E::A => ${1:todo!()}, - _ => ${0:todo!()}, + _ => ${2:todo!()},$0 } } "#, @@ -1790,7 +1799,7 @@ pub enum E { A, #[doc(hidden)] B }"#, fn foo(t: ::e::E) { match t { e::E::A => todo!(), - ${1:_} => ${0:todo!()}, + ${1:_} => ${2:todo!()},$0 } } "#, @@ -1815,7 +1824,7 @@ pub enum E { #[doc(hidden)] A, }"#, fn foo(t: ::e::E, b: bool) { match t { _ if b => todo!(), - ${1:_} => ${0:todo!()}, + ${1:_} => ${2:todo!()},$0 } } "#, @@ -1857,7 +1866,7 @@ pub enum E { A, #[doc(hidden)] B, }"#, fn foo(t: ::e::E) { match t { e::E::A => ${1:todo!()}, - _ => ${0:todo!()}, + _ => ${2:todo!()},$0 } } "#, @@ -1881,7 +1890,7 @@ enum E { A, #[doc(hidden)] B, } fn foo(t: E) { match t { E::A => ${1:todo!()}, - E::B => ${0:todo!()}, + E::B => ${2:todo!()},$0 } }"#, ); @@ -1906,7 +1915,7 @@ enum E { A, B, } fn foo(t: E) { match t { E::A => ${1:todo!()}, - E::B => ${0:todo!()}, + E::B => ${2:todo!()},$0 } }"#, ); @@ -1931,7 +1940,7 @@ enum E { A, #[doc(hidden)] B, } fn foo(t: E) { match t { E::A => ${1:todo!()}, - E::B => ${0:todo!()}, + E::B => ${2:todo!()},$0 } }"#, ); @@ -1982,7 +1991,7 @@ fn a() { let b = A::A; match b { A::A => ${1:todo!()}, - A::Missing { a, u32, c } => ${0:todo!()}, + A::Missing { a, u32, c } => ${2:todo!()},$0 } }"#, ) @@ -2020,7 +2029,7 @@ fn f() { let value = E::A; match value { E::A => ${1:todo!()}, - E::B(s) => ${0:todo!()}, + E::B(s) => ${2:todo!()},$0 } } "#, @@ -2058,7 +2067,7 @@ fn f() { let value = E::A; match value { E::A => ${1:todo!()}, - E::B(s1, s2) => ${0:todo!()}, + E::B(s1, s2) => ${2:todo!()},$0 } } "#, diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs b/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs index 8fffe7713f95b..eef4da55e94a5 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs @@ -188,7 +188,7 @@ enum Action { Move { distance: u32 }, Stop } fn handle(action: Action) { match action { Action::Move { distance } => ${1:todo!()}, - Action::Stop => ${0:todo!()}, + Action::Stop => ${2:todo!()},$0 } } "#####, From c588849044a09ba5e3c7dd74a31cd8038342f6cb Mon Sep 17 00:00:00 2001 From: David Kurilla <130074511+davidkurilla@users.noreply.github.com> Date: Wed, 6 Nov 2024 14:45:00 +0000 Subject: [PATCH 03/17] feat: convert add_braces to SyntaxFactory SyntaxEditor abstraction --- .../crates/ide-assists/src/handlers/add_braces.rs | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_braces.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_braces.rs index 2f4a263ee0700..c96ae7a16bc12 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_braces.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_braces.rs @@ -1,5 +1,5 @@ use syntax::{ - ast::{self, edit::AstNodeEdit, make}, + ast::{self, edit::AstNodeEdit, make, syntax_factory::SyntaxFactory}, syntax_editor::SyntaxEditor, AstNode, }; @@ -39,12 +39,19 @@ pub(crate) fn add_braces(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<( }, expr.syntax().text_range(), |builder| { + + let make = SyntaxFactory::new(); + let mut editor = builder.make_editor(&expr.syntax()); + let block_expr = AstNodeEdit::indent( - &make::block_expr(None, Some(expr.clone())), + &make.block_expr(None, Some(expr.clone())), AstNodeEdit::indent_level(&expr), ); - builder.replace(expr.syntax().text_range(), block_expr.syntax().text()); + editor.replace(expr.syntax(), block_expr.syntax()); + + editor.add_mappings(make.finish_with_mappings()); + builder.add_file_edits(ctx.file_id(), editor); }, ) } From 421661553fa550fbdb1c011e8930443ae09e5519 Mon Sep 17 00:00:00 2001 From: David Kurilla <130074511+davidkurilla@users.noreply.github.com> Date: Tue, 12 Nov 2024 22:43:48 +0000 Subject: [PATCH 04/17] fix: fix immutable tree error --- .../crates/ide-assists/src/handlers/add_braces.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_braces.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_braces.rs index c96ae7a16bc12..5ffaaebc9ea2a 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_braces.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_braces.rs @@ -1,5 +1,5 @@ use syntax::{ - ast::{self, edit::AstNodeEdit, make, syntax_factory::SyntaxFactory}, syntax_editor::SyntaxEditor, + ast::{self, edit::AstNodeEdit, edit_in_place, make, syntax_factory::SyntaxFactory}, syntax_editor::SyntaxEditor, AstNode, }; @@ -43,10 +43,8 @@ pub(crate) fn add_braces(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<( let make = SyntaxFactory::new(); let mut editor = builder.make_editor(&expr.syntax()); - let block_expr = AstNodeEdit::indent( - &make.block_expr(None, Some(expr.clone())), - AstNodeEdit::indent_level(&expr), - ); + let block_expr = make.block_expr(None, Some(expr.clone())); + block_expr.indent(expr.indent_level()); editor.replace(expr.syntax(), block_expr.syntax()); From 90857446625c7c0be4f623c8617066cd5cd21258 Mon Sep 17 00:00:00 2001 From: David Kurilla <130074511+davidkurilla@users.noreply.github.com> Date: Tue, 12 Nov 2024 23:58:24 +0000 Subject: [PATCH 05/17] fix: fix indentation error --- .../rust-analyzer/crates/ide-assists/src/handlers/add_braces.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_braces.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_braces.rs index 5ffaaebc9ea2a..9f93f16c0f67a 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_braces.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_braces.rs @@ -1,5 +1,5 @@ use syntax::{ - ast::{self, edit::AstNodeEdit, edit_in_place, make, syntax_factory::SyntaxFactory}, syntax_editor::SyntaxEditor, + ast::{self, edit_in_place::Indent, make, syntax_factory::SyntaxFactory}, syntax_editor::SyntaxEditor, AstNode, }; From 5458612e0454a812381deef4059bc46260091420 Mon Sep 17 00:00:00 2001 From: David Kurilla <130074511+davidkurilla@users.noreply.github.com> Date: Wed, 13 Nov 2024 00:06:12 +0000 Subject: [PATCH 06/17] fix: remove unused imports --- .../rust-analyzer/crates/ide-assists/src/handlers/add_braces.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_braces.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_braces.rs index 9f93f16c0f67a..dfbecc7cffcba 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_braces.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_braces.rs @@ -1,5 +1,5 @@ use syntax::{ - ast::{self, edit_in_place::Indent, make, syntax_factory::SyntaxFactory}, syntax_editor::SyntaxEditor, + ast::{self, edit_in_place::Indent, syntax_factory::SyntaxFactory}, AstNode, }; From 34dd288376f0e2268c95ee9492c5a03218c18aa9 Mon Sep 17 00:00:00 2001 From: David Kurilla <130074511+davidkurilla@users.noreply.github.com> Date: Fri, 15 Nov 2024 18:02:16 +0000 Subject: [PATCH 07/17] style: cargo fmt --- .../rust-analyzer/crates/ide-assists/src/handlers/add_braces.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_braces.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_braces.rs index dfbecc7cffcba..c17d9c5ccd15c 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_braces.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_braces.rs @@ -39,7 +39,6 @@ pub(crate) fn add_braces(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<( }, expr.syntax().text_range(), |builder| { - let make = SyntaxFactory::new(); let mut editor = builder.make_editor(&expr.syntax()); From c627c1a294a95b6775c01bc68c63ad4193ecf91c Mon Sep 17 00:00:00 2001 From: David Kurilla <130074511+davidkurilla@users.noreply.github.com> Date: Fri, 15 Nov 2024 19:08:01 +0000 Subject: [PATCH 08/17] style: remove needless borrow --- .../rust-analyzer/crates/ide-assists/src/handlers/add_braces.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_braces.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_braces.rs index c17d9c5ccd15c..42f615e71daf6 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_braces.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_braces.rs @@ -40,7 +40,7 @@ pub(crate) fn add_braces(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<( expr.syntax().text_range(), |builder| { let make = SyntaxFactory::new(); - let mut editor = builder.make_editor(&expr.syntax()); + let mut editor = builder.make_editor(expr.syntax()); let block_expr = make.block_expr(None, Some(expr.clone())); block_expr.indent(expr.indent_level()); From a96a0934de14b4bd921b43695a1b50ea72f3077d Mon Sep 17 00:00:00 2001 From: Tarek Date: Sun, 17 Nov 2024 12:17:44 +0200 Subject: [PATCH 09/17] =?UTF-8?q?feat:=20migrate=C2=A0`reorder=5Fimpl=5Fit?= =?UTF-8?q?ems`=C2=A0assist=20to=20use=C2=A0`SyntaxFactory`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Tarek --- .../src/handlers/reorder_impl_items.rs | 21 ++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/reorder_impl_items.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/reorder_impl_items.rs index ada89ce7c40ac..d7fa8826125b6 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/reorder_impl_items.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/reorder_impl_items.rs @@ -3,7 +3,7 @@ use ide_db::{FxHashMap, RootDatabase}; use itertools::Itertools; use syntax::{ ast::{self, HasName}, - ted, AstNode, + AstNode, SyntaxElement, }; use crate::{AssistContext, AssistId, AssistKind, Assists}; @@ -46,6 +46,11 @@ pub(crate) fn reorder_impl_items(acc: &mut Assists, ctx: &AssistContext<'_>) -> let impl_ast = ctx.find_node_at_offset::()?; let items = impl_ast.assoc_item_list()?; + let parent_node = match ctx.covering_element() { + SyntaxElement::Node(n) => n, + SyntaxElement::Token(t) => t.parent()?, + }; + // restrict the range // if cursor is in assoc_items, abort let assoc_range = items.syntax().text_range(); @@ -94,12 +99,14 @@ pub(crate) fn reorder_impl_items(acc: &mut Assists, ctx: &AssistContext<'_>) -> "Sort items by trait definition", target, |builder| { - let assoc_items = - assoc_items.into_iter().map(|item| builder.make_mut(item)).collect::>(); - assoc_items - .into_iter() - .zip(sorted) - .for_each(|(old, new)| ted::replace(old.syntax(), new.clone_for_update().syntax())); + let mut editor = builder.make_editor(&parent_node); + + assoc_items.into_iter().zip(sorted).for_each(|(old, new)| { + // FIXME: remove `clone_for_update` when `SyntaxEditor` handles it for us + editor.replace(old.syntax(), new.clone_for_update().syntax()) + }); + + builder.add_file_edits(ctx.file_id(), editor); }, ) } From b4a31683c1e9c0b624c4c5341708e9dd1b8698b9 Mon Sep 17 00:00:00 2001 From: David Richey Date: Thu, 14 Nov 2024 12:12:43 -0600 Subject: [PATCH 10/17] Re-add rust-analyzer.cargo.sysrootQueryMetadata --- .../project-model/src/cargo_workspace.rs | 4 +- .../crates/project-model/src/lib.rs | 7 +++ .../crates/project-model/src/sysroot.rs | 55 ++++++++++++----- .../crates/project-model/src/tests.rs | 6 +- .../crates/project-model/src/workspace.rs | 61 ++++++++++--------- .../rust-analyzer/src/cli/analysis_stats.rs | 4 ++ .../crates/rust-analyzer/src/cli/flags.rs | 4 ++ .../rust-analyzer/src/cli/rustc_tests.rs | 8 ++- .../crates/rust-analyzer/src/config.rs | 24 ++++++++ .../crates/rust-analyzer/src/reload.rs | 4 +- .../docs/user/generated_config.adoc | 6 ++ .../rust-analyzer/editors/code/package.json | 18 ++++++ 12 files changed, 150 insertions(+), 51 deletions(-) diff --git a/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs b/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs index 2dc6f0357e3d8..cb5738a3b4094 100644 --- a/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs +++ b/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs @@ -13,7 +13,7 @@ use serde_json::from_value; use span::Edition; use toolchain::Tool; -use crate::{utf8_stdout, ManifestPath, Sysroot}; +use crate::{utf8_stdout, ManifestPath, Sysroot, SysrootQueryMetadata}; use crate::{CfgOverrides, InvocationStrategy}; /// [`CargoWorkspace`] represents the logical structure of, well, a Cargo @@ -85,6 +85,8 @@ pub struct CargoConfig { pub target: Option, /// Sysroot loading behavior pub sysroot: Option, + /// How to query metadata for the sysroot crate. + pub sysroot_query_metadata: SysrootQueryMetadata, pub sysroot_src: Option, /// rustc private crate source pub rustc_source: Option, diff --git a/src/tools/rust-analyzer/crates/project-model/src/lib.rs b/src/tools/rust-analyzer/crates/project-model/src/lib.rs index 91bdef4889ca1..da8afc5d3a184 100644 --- a/src/tools/rust-analyzer/crates/project-model/src/lib.rs +++ b/src/tools/rust-analyzer/crates/project-model/src/lib.rs @@ -240,3 +240,10 @@ fn parse_cfg(s: &str) -> Result { }; Ok(res) } + +#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)] +pub enum SysrootQueryMetadata { + #[default] + CargoMetadata, + None, +} diff --git a/src/tools/rust-analyzer/crates/project-model/src/sysroot.rs b/src/tools/rust-analyzer/crates/project-model/src/sysroot.rs index 19f4c35b5addd..8df49608c0708 100644 --- a/src/tools/rust-analyzer/crates/project-model/src/sysroot.rs +++ b/src/tools/rust-analyzer/crates/project-model/src/sysroot.rs @@ -14,7 +14,7 @@ use paths::{AbsPath, AbsPathBuf, Utf8PathBuf}; use rustc_hash::FxHashMap; use toolchain::{probe_for_binary, Tool}; -use crate::{utf8_stdout, CargoConfig, CargoWorkspace, ManifestPath}; +use crate::{utf8_stdout, CargoConfig, CargoWorkspace, ManifestPath, SysrootQueryMetadata}; #[derive(Debug, Clone, PartialEq, Eq)] pub struct Sysroot { @@ -123,27 +123,43 @@ impl Sysroot { // FIXME: Expose a builder api as loading the sysroot got way too modular and complicated. impl Sysroot { /// Attempts to discover the toolchain's sysroot from the given `dir`. - pub fn discover(dir: &AbsPath, extra_env: &FxHashMap) -> Sysroot { + pub fn discover( + dir: &AbsPath, + extra_env: &FxHashMap, + sysroot_query_metadata: SysrootQueryMetadata, + ) -> Sysroot { let sysroot_dir = discover_sysroot_dir(dir, extra_env); let sysroot_src_dir = sysroot_dir.as_ref().ok().map(|sysroot_dir| { discover_sysroot_src_dir_or_add_component(sysroot_dir, dir, extra_env) }); - Sysroot::load_core_check(Some(sysroot_dir), sysroot_src_dir) + Sysroot::load_core_check(Some(sysroot_dir), sysroot_src_dir, sysroot_query_metadata) } pub fn discover_with_src_override( current_dir: &AbsPath, extra_env: &FxHashMap, sysroot_src_dir: AbsPathBuf, + sysroot_query_metadata: SysrootQueryMetadata, ) -> Sysroot { let sysroot_dir = discover_sysroot_dir(current_dir, extra_env); - Sysroot::load_core_check(Some(sysroot_dir), Some(Ok(sysroot_src_dir))) + Sysroot::load_core_check( + Some(sysroot_dir), + Some(Ok(sysroot_src_dir)), + sysroot_query_metadata, + ) } - pub fn discover_sysroot_src_dir(sysroot_dir: AbsPathBuf) -> Sysroot { + pub fn discover_sysroot_src_dir( + sysroot_dir: AbsPathBuf, + sysroot_query_metadata: SysrootQueryMetadata, + ) -> Sysroot { let sysroot_src_dir = discover_sysroot_src_dir(&sysroot_dir) .ok_or_else(|| format_err!("can't find standard library sources in {sysroot_dir}")); - Sysroot::load_core_check(Some(Ok(sysroot_dir)), Some(sysroot_src_dir)) + Sysroot::load_core_check( + Some(Ok(sysroot_dir)), + Some(sysroot_src_dir), + sysroot_query_metadata, + ) } pub fn discover_rustc_src(&self) -> Option { @@ -186,15 +202,20 @@ impl Sysroot { }) } - pub fn load(sysroot_dir: Option, sysroot_src_dir: Option) -> Sysroot { - Self::load_core_check(sysroot_dir.map(Ok), sysroot_src_dir.map(Ok)) + pub fn load( + sysroot_dir: Option, + sysroot_src_dir: Option, + sysroot_query_metadata: SysrootQueryMetadata, + ) -> Sysroot { + Self::load_core_check(sysroot_dir.map(Ok), sysroot_src_dir.map(Ok), sysroot_query_metadata) } fn load_core_check( sysroot_dir: Option>, sysroot_src_dir: Option>, + sysroot_query_metadata: SysrootQueryMetadata, ) -> Sysroot { - let mut sysroot = Self::load_(sysroot_dir, sysroot_src_dir); + let mut sysroot = Self::load_(sysroot_dir, sysroot_src_dir, sysroot_query_metadata); if sysroot.error.is_none() { if let Some(src_root) = &sysroot.src_root { let has_core = match &sysroot.mode { @@ -220,6 +241,7 @@ impl Sysroot { fn load_( sysroot_dir: Option>, sysroot_src_dir: Option>, + sysroot_query_metadata: SysrootQueryMetadata, ) -> Sysroot { let sysroot_dir = match sysroot_dir { Some(Ok(sysroot_dir)) => Some(sysroot_dir), @@ -252,12 +274,15 @@ impl Sysroot { } } }; - let library_manifest = ManifestPath::try_from(sysroot_src_dir.join("Cargo.toml")).unwrap(); - if fs::metadata(&library_manifest).is_ok() { - if let Some(sysroot) = - Self::load_library_via_cargo(library_manifest, &sysroot_dir, &sysroot_src_dir) - { - return sysroot; + if sysroot_query_metadata == SysrootQueryMetadata::CargoMetadata { + let library_manifest = + ManifestPath::try_from(sysroot_src_dir.join("Cargo.toml")).unwrap(); + if fs::metadata(&library_manifest).is_ok() { + if let Some(sysroot) = + Self::load_library_via_cargo(library_manifest, &sysroot_dir, &sysroot_src_dir) + { + return sysroot; + } } } tracing::debug!("Stitching sysroot library: {sysroot_src_dir}"); diff --git a/src/tools/rust-analyzer/crates/project-model/src/tests.rs b/src/tools/rust-analyzer/crates/project-model/src/tests.rs index ef115494a8886..f3cf2d83eaca6 100644 --- a/src/tools/rust-analyzer/crates/project-model/src/tests.rs +++ b/src/tools/rust-analyzer/crates/project-model/src/tests.rs @@ -13,7 +13,8 @@ use triomphe::Arc; use crate::{ sysroot::SysrootMode, workspace::ProjectWorkspaceKind, CargoWorkspace, CfgOverrides, - ManifestPath, ProjectJson, ProjectJsonData, ProjectWorkspace, Sysroot, WorkspaceBuildScripts, + ManifestPath, ProjectJson, ProjectJsonData, ProjectWorkspace, Sysroot, SysrootQueryMetadata, + WorkspaceBuildScripts, }; fn load_cargo(file: &str) -> (CrateGraph, ProcMacroPaths) { @@ -116,7 +117,7 @@ fn get_fake_sysroot() -> Sysroot { // fake sysroot, so we give them both the same path: let sysroot_dir = AbsPathBuf::assert(sysroot_path); let sysroot_src_dir = sysroot_dir.clone(); - Sysroot::load(Some(sysroot_dir), Some(sysroot_src_dir)) + Sysroot::load(Some(sysroot_dir), Some(sysroot_src_dir), SysrootQueryMetadata::CargoMetadata) } fn rooted_project_json(data: ProjectJsonData) -> ProjectJson { @@ -231,6 +232,7 @@ fn smoke_test_real_sysroot_cargo() { let sysroot = Sysroot::discover( AbsPath::assert(Utf8Path::new(env!("CARGO_MANIFEST_DIR"))), &Default::default(), + SysrootQueryMetadata::CargoMetadata, ); assert!(matches!(sysroot.mode(), SysrootMode::Workspace(_))); let project_workspace = ProjectWorkspace { diff --git a/src/tools/rust-analyzer/crates/project-model/src/workspace.rs b/src/tools/rust-analyzer/crates/project-model/src/workspace.rs index d53639e242320..f5ba71fcd05ff 100644 --- a/src/tools/rust-analyzer/crates/project-model/src/workspace.rs +++ b/src/tools/rust-analyzer/crates/project-model/src/workspace.rs @@ -211,34 +211,35 @@ impl ProjectWorkspace { let project_location = project_json.parent().to_path_buf(); let project_json: ProjectJson = ProjectJson::new(Some(project_json.clone()), &project_location, data); - ProjectWorkspace::load_inline( - project_json, - config.target.as_deref(), - &config.extra_env, - &config.cfg_overrides, - ) + ProjectWorkspace::load_inline(project_json, config) } ProjectManifest::CargoScript(rust_file) => { ProjectWorkspace::load_detached_file(rust_file, config)? } ProjectManifest::CargoToml(cargo_toml) => { let sysroot = match (&config.sysroot, &config.sysroot_src) { - (Some(RustLibSource::Discover), None) => { - Sysroot::discover(cargo_toml.parent(), &config.extra_env) - } + (Some(RustLibSource::Discover), None) => Sysroot::discover( + cargo_toml.parent(), + &config.extra_env, + config.sysroot_query_metadata, + ), (Some(RustLibSource::Discover), Some(sysroot_src)) => { Sysroot::discover_with_src_override( cargo_toml.parent(), &config.extra_env, sysroot_src.clone(), + config.sysroot_query_metadata, ) } - (Some(RustLibSource::Path(path)), None) => { - Sysroot::discover_sysroot_src_dir(path.clone()) - } - (Some(RustLibSource::Path(sysroot)), Some(sysroot_src)) => { - Sysroot::load(Some(sysroot.clone()), Some(sysroot_src.clone())) - } + (Some(RustLibSource::Path(path)), None) => Sysroot::discover_sysroot_src_dir( + path.clone(), + config.sysroot_query_metadata, + ), + (Some(RustLibSource::Path(sysroot)), Some(sysroot_src)) => Sysroot::load( + Some(sysroot.clone()), + Some(sysroot_src.clone()), + config.sysroot_query_metadata, + ), (None, _) => Sysroot::empty(), }; tracing::info!(workspace = %cargo_toml, src_root = ?sysroot.src_root(), root = ?sysroot.root(), "Using sysroot"); @@ -352,20 +353,19 @@ impl ProjectWorkspace { Ok(res) } - pub fn load_inline( - project_json: ProjectJson, - target: Option<&str>, - extra_env: &FxHashMap, - cfg_overrides: &CfgOverrides, - ) -> ProjectWorkspace { - let sysroot = Sysroot::load(project_json.sysroot.clone(), project_json.sysroot_src.clone()); + pub fn load_inline(project_json: ProjectJson, config: &CargoConfig) -> ProjectWorkspace { + let sysroot = Sysroot::load( + project_json.sysroot.clone(), + project_json.sysroot_src.clone(), + config.sysroot_query_metadata, + ); let cfg_config = RustcCfgConfig::Rustc(&sysroot); let data_layout_config = RustcDataLayoutConfig::Rustc(&sysroot); let toolchain = match get_toolchain_version( project_json.path(), &sysroot, Tool::Rustc, - extra_env, + &config.extra_env, "rustc ", ) { Ok(it) => it, @@ -375,15 +375,16 @@ impl ProjectWorkspace { } }; - let rustc_cfg = rustc_cfg::get(target, extra_env, cfg_config); - let data_layout = target_data_layout::get(data_layout_config, target, extra_env); + let target = config.target.as_deref(); + let rustc_cfg = rustc_cfg::get(target, &config.extra_env, cfg_config); + let data_layout = target_data_layout::get(data_layout_config, target, &config.extra_env); ProjectWorkspace { kind: ProjectWorkspaceKind::Json(project_json), sysroot, rustc_cfg, toolchain, target_layout: data_layout.map(Arc::from).map_err(|it| Arc::from(it.to_string())), - cfg_overrides: cfg_overrides.clone(), + cfg_overrides: config.cfg_overrides.clone(), } } @@ -393,8 +394,12 @@ impl ProjectWorkspace { ) -> anyhow::Result { let dir = detached_file.parent(); let sysroot = match &config.sysroot { - Some(RustLibSource::Path(path)) => Sysroot::discover_sysroot_src_dir(path.clone()), - Some(RustLibSource::Discover) => Sysroot::discover(dir, &config.extra_env), + Some(RustLibSource::Path(path)) => { + Sysroot::discover_sysroot_src_dir(path.clone(), config.sysroot_query_metadata) + } + Some(RustLibSource::Discover) => { + Sysroot::discover(dir, &config.extra_env, config.sysroot_query_metadata) + } None => Sysroot::empty(), }; diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs index 155fb6f7c88c0..802d0c69a47af 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs @@ -65,6 +65,10 @@ impl flags::AnalysisStats { true => None, false => Some(RustLibSource::Discover), }, + sysroot_query_metadata: match self.no_query_sysroot_metadata { + true => project_model::SysrootQueryMetadata::None, + false => project_model::SysrootQueryMetadata::CargoMetadata, + }, all_targets: true, set_test: !self.no_test, cfg_overrides: CfgOverrides { diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/flags.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/flags.rs index ff24602144a9d..920a2a37efb69 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/flags.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/flags.rs @@ -71,6 +71,9 @@ xflags::xflags! { optional --with-deps /// Don't load sysroot crates (`std`, `core` & friends). optional --no-sysroot + /// Don't run cargo metadata on the sysroot to analyze its third-party dependencies. + /// Requires --no-sysroot to not be set. + optional --no-query-sysroot-metadata /// Don't set #[cfg(test)]. optional --no-test @@ -235,6 +238,7 @@ pub struct AnalysisStats { pub only: Option, pub with_deps: bool, pub no_sysroot: bool, + pub no_query_sysroot_metadata: bool, pub no_test: bool, pub disable_build_scripts: bool, pub disable_proc_macros: bool, diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/rustc_tests.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/rustc_tests.rs index 30378db0b388b..6483afc85b21d 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/rustc_tests.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/rustc_tests.rs @@ -13,7 +13,7 @@ use profile::StopWatch; use project_model::target_data_layout::RustcDataLayoutConfig; use project_model::{ target_data_layout, CargoConfig, ManifestPath, ProjectWorkspace, ProjectWorkspaceKind, - RustLibSource, Sysroot, + RustLibSource, Sysroot, SysrootQueryMetadata, }; use load_cargo::{load_workspace, LoadCargoConfig, ProcMacroServerChoice}; @@ -74,7 +74,11 @@ impl Tester { ..Default::default() }; - let sysroot = Sysroot::discover(tmp_file.parent().unwrap(), &cargo_config.extra_env); + let sysroot = Sysroot::discover( + tmp_file.parent().unwrap(), + &cargo_config.extra_env, + SysrootQueryMetadata::CargoMetadata, + ); let data_layout = target_data_layout::get( RustcDataLayoutConfig::Rustc(&sysroot), None, diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs index f5b0fcecf3901..37d45255e29d1 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs @@ -558,6 +558,9 @@ config_data! { /// /// This option does not take effect until rust-analyzer is restarted. cargo_sysroot: Option = Some("discover".to_owned()), + /// How to query metadata for the sysroot crate. Using cargo metadata allows rust-analyzer + /// to analyze third-party dependencies of the standard libraries. + cargo_sysrootQueryMetadata: SysrootQueryMetadata = SysrootQueryMetadata::CargoMetadata, /// Relative path to the sysroot library sources. If left unset, this will default to /// `{cargo.sysroot}/lib/rustlib/src/rust/library`. /// @@ -1868,6 +1871,12 @@ impl Config { }, target: self.cargo_target(source_root).clone(), sysroot, + sysroot_query_metadata: match self.cargo_sysrootQueryMetadata(None) { + SysrootQueryMetadata::CargoMetadata => { + project_model::SysrootQueryMetadata::CargoMetadata + } + SysrootQueryMetadata::None => project_model::SysrootQueryMetadata::None, + }, sysroot_src, rustc_source, cfg_overrides: project_model::CfgOverrides { @@ -2559,6 +2568,13 @@ pub enum NumThreads { Concrete(usize), } +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] +#[serde(rename_all = "snake_case")] +pub enum SysrootQueryMetadata { + CargoMetadata, + None, +} + macro_rules! _default_val { (@verbatim: $s:literal, $ty:ty) => {{ let default_: $ty = serde_json::from_str(&$s).unwrap(); @@ -3410,6 +3426,14 @@ fn field_props(field: &str, ty: &str, doc: &[&str], default: &str) -> serde_json } ] }, + "SysrootQueryMetadata" => set! { + "type": "string", + "enum": ["none", "cargo_metadata"], + "enumDescriptions": [ + "Do not query sysroot metadata, always use stitched sysroot.", + "Use `cargo metadata` to query sysroot metadata." + ], + }, _ => panic!("missing entry for {ty}: {default} (field {field})"), } diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs index 0b24833358ddd..bc85afa0e4941 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs @@ -316,9 +316,7 @@ impl GlobalState { LinkedProject::InlineJsonProject(it) => { let workspace = project_model::ProjectWorkspace::load_inline( it.clone(), - cargo_config.target.as_deref(), - &cargo_config.extra_env, - &cargo_config.cfg_overrides, + &cargo_config, ); Ok(workspace) } diff --git a/src/tools/rust-analyzer/docs/user/generated_config.adoc b/src/tools/rust-analyzer/docs/user/generated_config.adoc index 463718835b91f..052d0a2a41d0c 100644 --- a/src/tools/rust-analyzer/docs/user/generated_config.adoc +++ b/src/tools/rust-analyzer/docs/user/generated_config.adoc @@ -135,6 +135,12 @@ Unsetting this disables sysroot loading. This option does not take effect until rust-analyzer is restarted. -- +[[rust-analyzer.cargo.sysrootQueryMetadata]]rust-analyzer.cargo.sysrootQueryMetadata (default: `"cargo_metadata"`):: ++ +-- +How to query metadata for the sysroot crate. Using cargo metadata allows rust-analyzer +to analyze third-party dependencies of the standard libraries. +-- [[rust-analyzer.cargo.sysrootSrc]]rust-analyzer.cargo.sysrootSrc (default: `null`):: + -- diff --git a/src/tools/rust-analyzer/editors/code/package.json b/src/tools/rust-analyzer/editors/code/package.json index b868622b3a520..82c43b76fdd56 100644 --- a/src/tools/rust-analyzer/editors/code/package.json +++ b/src/tools/rust-analyzer/editors/code/package.json @@ -816,6 +816,24 @@ } } }, + { + "title": "cargo", + "properties": { + "rust-analyzer.cargo.sysrootQueryMetadata": { + "markdownDescription": "How to query metadata for the sysroot crate. Using cargo metadata allows rust-analyzer\nto analyze third-party dependencies of the standard libraries.", + "default": "cargo_metadata", + "type": "string", + "enum": [ + "none", + "cargo_metadata" + ], + "enumDescriptions": [ + "Do not query sysroot metadata, always use stitched sysroot.", + "Use `cargo metadata` to query sysroot metadata." + ] + } + } + }, { "title": "cargo", "properties": { From effe9ac712da3ae7488c5b7f1211d2f2609a22d7 Mon Sep 17 00:00:00 2001 From: Christian Schwarz Date: Mon, 18 Nov 2024 23:07:19 +0100 Subject: [PATCH 11/17] improve selection handling for `merge_match_arms` --- .../crates/ide-assists/src/assist_context.rs | 3 + .../src/handlers/merge_match_arms.rs | 101 +++++++++++++++++- 2 files changed, 103 insertions(+), 1 deletion(-) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/assist_context.rs b/src/tools/rust-analyzer/crates/ide-assists/src/assist_context.rs index 1d2d3350f7c76..0146369f298b5 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/assist_context.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/assist_context.rs @@ -116,6 +116,9 @@ impl<'a> AssistContext<'a> { pub(crate) fn find_node_at_offset(&self) -> Option { find_node_at_offset(self.source_file.syntax(), self.offset()) } + pub(crate) fn find_node_at_trimmed_offset(&self) -> Option { + find_node_at_offset(self.source_file.syntax(), self.trimmed_range.start()) + } pub(crate) fn find_node_at_range(&self) -> Option { find_node_at_range(self.source_file.syntax(), self.trimmed_range) } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/merge_match_arms.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/merge_match_arms.rs index 4608e9494bca1..f83de931eaba7 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/merge_match_arms.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/merge_match_arms.rs @@ -34,7 +34,7 @@ use crate::{AssistContext, AssistId, AssistKind, Assists, TextRange}; // } // ``` pub(crate) fn merge_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { - let current_arm = ctx.find_node_at_offset::()?; + let current_arm = ctx.find_node_at_trimmed_offset::()?; // Don't try to handle arms with guards for now - can add support for this later if current_arm.guard().is_some() { return None; @@ -42,12 +42,21 @@ pub(crate) fn merge_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>) -> Op let current_expr = current_arm.expr()?; let current_text_range = current_arm.syntax().text_range(); let current_arm_types = get_arm_types(ctx, ¤t_arm); + let multi_arm_selection = !ctx.has_empty_selection() + && ctx.selection_trimmed().end() > current_arm.syntax().text_range().end(); // We check if the following match arms match this one. We could, but don't, // compare to the previous match arm as well. let arms_to_merge = successors(Some(current_arm), |it| neighbor(it, Direction::Next)) .take_while(|arm| match arm.expr() { Some(expr) if arm.guard().is_none() => { + // don't include match arms that start after our selection + if multi_arm_selection + && arm.syntax().text_range().start() >= ctx.selection_trimmed().end() + { + return false; + } + let same_text = expr.syntax().text() == current_expr.syntax().text(); if !same_text { return false; @@ -298,6 +307,96 @@ fn main() { ) } + #[test] + fn merge_match_arms_selection_has_leading_whitespace() { + check_assist( + merge_match_arms, + r#" +#[derive(Debug)] +enum X { A, B, C } + +fn main() { + match X::A { + $0 X::A => 0, + X::B => 0,$0 + X::C => 1, + } +} +"#, + r#" +#[derive(Debug)] +enum X { A, B, C } + +fn main() { + match X::A { + X::A | X::B => 0, + X::C => 1, + } +} +"#, + ); + } + + #[test] + fn merge_match_arms_stops_at_end_of_selection() { + check_assist( + merge_match_arms, + r#" +#[derive(Debug)] +enum X { A, B, C } + +fn main() { + match X::A { + $0 X::A => 0, + X::B => 0, + $0X::C => 0, + } +} +"#, + r#" +#[derive(Debug)] +enum X { A, B, C } + +fn main() { + match X::A { + X::A | X::B => 0, + X::C => 0, + } +} +"#, + ); + } + + #[test] + fn merge_match_arms_works_despite_accidental_selection() { + check_assist( + merge_match_arms, + r#" +#[derive(Debug)] +enum X { A, B, C } + +fn main() { + match X::A { + X::$0A$0 => 0, + X::B => 0, + X::C => 1, + } +} +"#, + r#" +#[derive(Debug)] +enum X { A, B, C } + +fn main() { + match X::A { + X::A | X::B => 0, + X::C => 1, + } +} +"#, + ); + } + #[test] fn merge_match_arms_rejects_guards() { check_assist_not_applicable( From a3efe3bc29abbb70da0c2836eef769e40c85dfe9 Mon Sep 17 00:00:00 2001 From: Mark Murphy Date: Sat, 23 Nov 2024 13:46:40 -0500 Subject: [PATCH 12/17] Update request entry point file path in architecture.md --- src/tools/rust-analyzer/docs/dev/architecture.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/rust-analyzer/docs/dev/architecture.md b/src/tools/rust-analyzer/docs/dev/architecture.md index 6aa57b2f9be95..9c9e05a429bf8 100644 --- a/src/tools/rust-analyzer/docs/dev/architecture.md +++ b/src/tools/rust-analyzer/docs/dev/architecture.md @@ -42,7 +42,7 @@ The underlying engine makes sure that model is computed lazily (on-demand) and c `crates/rust-analyzer/src/bin/main.rs` contains the main function which spawns LSP. This is *the* entry point, but it front-loads a lot of complexity, so it's fine to just skim through it. -`crates/rust-analyzer/src/handlers/requests.rs` implements all LSP requests and is a great place to start if you are already familiar with LSP. +`crates/rust-analyzer/src/handlers/request.rs` implements all LSP requests and is a great place to start if you are already familiar with LSP. `Analysis` and `AnalysisHost` types define the main API for consumers of IDE services. From 63b82dd0415f8902d22d7db630d6c0fc04366946 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= Date: Sun, 24 Nov 2024 18:26:26 +0200 Subject: [PATCH 13/17] Fix missing rust-src message --- .../rust-analyzer/crates/project-model/src/sysroot.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/tools/rust-analyzer/crates/project-model/src/sysroot.rs b/src/tools/rust-analyzer/crates/project-model/src/sysroot.rs index 19f4c35b5addd..d47b4976aa27c 100644 --- a/src/tools/rust-analyzer/crates/project-model/src/sysroot.rs +++ b/src/tools/rust-analyzer/crates/project-model/src/sysroot.rs @@ -444,13 +444,14 @@ fn discover_sysroot_src_dir_or_add_component( get_rust_src(sysroot_path) }) .ok_or_else(|| { - let error = "\ + tracing::error!(%sysroot_path, "can't load standard library, try installing `rust-src`"); + format_err!( + "\ can't load standard library from sysroot {sysroot_path} (discovered via `rustc --print sysroot`) -try installing the Rust source the same way you installed rustc"; - tracing::error!(error); - format_err!(error) +try installing `rust-src` the same way you installed `rustc`" + ) }) } From b4a23bb3fce5b661b6071deb0745a46f0b057868 Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Mon, 25 Nov 2024 18:44:41 +0200 Subject: [PATCH 14/17] Fix a stack overflow when computing the sizedness of a struct that includes itself as the tail field --- .../crates/hir-ty/src/infer/unify.rs | 36 +++++++++++++------ .../crates/hir-ty/src/tests/traits.rs | 21 +++++++++++ 2 files changed, 47 insertions(+), 10 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs index e4881d7520138..54aa18ce20766 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs @@ -916,6 +916,32 @@ impl<'a> InferenceTable<'a> { /// Check if given type is `Sized` or not pub(crate) fn is_sized(&mut self, ty: &Ty) -> bool { + let mut ty = ty.clone(); + { + let mut structs = SmallVec::<[_; 8]>::new(); + // Must use a loop here and not recursion because otherwise users will conduct completely + // artificial examples of structs that have themselves as the tail field and complain r-a crashes. + while let Some((AdtId::StructId(id), subst)) = ty.as_adt() { + let struct_data = self.db.struct_data(id); + if let Some((last_field, _)) = struct_data.variant_data.fields().iter().next_back() + { + let last_field_ty = self.db.field_types(id.into())[last_field] + .clone() + .substitute(Interner, subst); + if structs.contains(&ty) { + // A struct recursively contains itself as a tail field somewhere. + return true; // Don't overload the users with too many errors. + } + structs.push(ty); + // Structs can have DST as its last field and such cases are not handled + // as unsized by the chalk, so we do this manually. + ty = last_field_ty; + } else { + break; + }; + } + } + // Early return for some obvious types if matches!( ty.kind(Interner), @@ -930,16 +956,6 @@ impl<'a> InferenceTable<'a> { return true; } - if let Some((AdtId::StructId(id), subst)) = ty.as_adt() { - let struct_data = self.db.struct_data(id); - if let Some((last_field, _)) = struct_data.variant_data.fields().iter().last() { - let last_field_ty = - self.db.field_types(id.into())[last_field].clone().substitute(Interner, subst); - // Structs can have DST as its last field and such cases are not handled - // as unsized by the chalk, so we do this manually - return self.is_sized(&last_field_ty); - } - } let Some(sized) = self .db .lang_item(self.trait_env.krate, LangItem::Sized) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs index 9b982a124e7b2..624148cab20f2 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs @@ -4790,3 +4790,24 @@ fn allowed3(baz: impl Baz>) {} "#]], ) } + +#[test] +fn recursive_tail_sized() { + check_infer( + r#" +struct WeirdFoo(WeirdBar); +struct WeirdBar(WeirdFoo); + +fn bar(v: *const ()) { + let _ = v as *const WeirdFoo; +} + "#, + expect![[r#" + 62..63 'v': *const () + 76..113 '{ ...Foo; }': () + 86..87 '_': *const WeirdFoo + 90..91 'v': *const () + 90..110 'v as *...irdFoo': *const WeirdFoo + "#]], + ); +} From 6e3cb4abfbbdb6fb7e34eed99840d1fe22c6b682 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= Date: Thu, 28 Nov 2024 08:37:22 +0200 Subject: [PATCH 15/17] Preparing for merge from rust-lang/rust --- src/tools/rust-analyzer/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/rust-analyzer/rust-version b/src/tools/rust-analyzer/rust-version index 00f4f743a7c45..8f41ed9e14f95 100644 --- a/src/tools/rust-analyzer/rust-version +++ b/src/tools/rust-analyzer/rust-version @@ -1 +1 @@ -145f9cf95de1fbde3fa11e98461310e0373253e6 +f005c7437def424a1c43cbc380352a58d8ac920b From 1a435ed7edc19812c29006701b0106a0d0802542 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= Date: Thu, 28 Nov 2024 08:39:56 +0200 Subject: [PATCH 16/17] Bump rustc crates --- src/tools/rust-analyzer/Cargo.lock | 24 ++++++++++++------------ src/tools/rust-analyzer/Cargo.toml | 10 +++++----- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/tools/rust-analyzer/Cargo.lock b/src/tools/rust-analyzer/Cargo.lock index 019609e6a5beb..2bd4d17fe2226 100644 --- a/src/tools/rust-analyzer/Cargo.lock +++ b/src/tools/rust-analyzer/Cargo.lock @@ -1492,9 +1492,9 @@ dependencies = [ [[package]] name = "ra-ap-rustc_abi" -version = "0.76.0" +version = "0.80.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "709fde78db053c78c87776ec738677649f791645883f82ff145f68caf9f18e1a" +checksum = "613760a3071b25a67a8d7bc97b37c7fd4722562e9479137b83ae9cf8f8c1601a" dependencies = [ "bitflags 2.6.0", "ra-ap-rustc_index", @@ -1503,9 +1503,9 @@ dependencies = [ [[package]] name = "ra-ap-rustc_index" -version = "0.76.0" +version = "0.80.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da115d496e5abd65e2dceb6883d7597593badfe23fea3439202b8da5a11ea250" +checksum = "5b2bc6b4ecede8ff28295041e22c2e66853f8e0125990c05135bad3c30bad12c" dependencies = [ "arrayvec", "ra-ap-rustc_index_macros", @@ -1514,9 +1514,9 @@ dependencies = [ [[package]] name = "ra-ap-rustc_index_macros" -version = "0.76.0" +version = "0.80.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be86d06a75a8125c1ace197d5030e6e02721348d32e572baea35c891669ad1e2" +checksum = "2374a39fb2d92d0509178c2b442eadca3cc10e403ef9729a040c1855b08ff261" dependencies = [ "proc-macro2", "quote", @@ -1525,9 +1525,9 @@ dependencies = [ [[package]] name = "ra-ap-rustc_lexer" -version = "0.76.0" +version = "0.80.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b64b46ae0d8f59acc32e64e0085532b831f0d6182d870a7cd86c046c2c46e722" +checksum = "5a2cf8e48b69af3ecc29ed3449892e8a999111d2f75212a78aa242e117cf1711" dependencies = [ "unicode-properties", "unicode-xid", @@ -1535,9 +1535,9 @@ dependencies = [ [[package]] name = "ra-ap-rustc_parse_format" -version = "0.76.0" +version = "0.80.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbdaad19ddbd0ff46e947ca8dbb6ae678a112d3938669fb3ad6bfd244917e24b" +checksum = "8d6f59a22b559263c5c42747ae362cf5d4fb272293fa119a4623f8ec288f9656" dependencies = [ "ra-ap-rustc_index", "ra-ap-rustc_lexer", @@ -1545,9 +1545,9 @@ dependencies = [ [[package]] name = "ra-ap-rustc_pattern_analysis" -version = "0.76.0" +version = "0.80.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc5761e37c78d98ede9f20f6b66526093d0be66aa256d5cbdf214495843ba74d" +checksum = "a7d0575b54ffe09bc5d2f158454bc05f0c30c01d9992310965f854be50ae22b8" dependencies = [ "ra-ap-rustc_index", "rustc-hash 2.0.0", diff --git a/src/tools/rust-analyzer/Cargo.toml b/src/tools/rust-analyzer/Cargo.toml index 94e7de553bf49..632b290ba9844 100644 --- a/src/tools/rust-analyzer/Cargo.toml +++ b/src/tools/rust-analyzer/Cargo.toml @@ -84,11 +84,11 @@ tt = { path = "./crates/tt", version = "0.0.0" } vfs-notify = { path = "./crates/vfs-notify", version = "0.0.0" } vfs = { path = "./crates/vfs", version = "0.0.0" } -ra-ap-rustc_lexer = { version = "0.76", default-features = false } -ra-ap-rustc_parse_format = { version = "0.76", default-features = false } -ra-ap-rustc_index = { version = "0.76", default-features = false } -ra-ap-rustc_abi = { version = "0.76", default-features = false } -ra-ap-rustc_pattern_analysis = { version = "0.76", default-features = false } +ra-ap-rustc_lexer = { version = "0.80", default-features = false } +ra-ap-rustc_parse_format = { version = "0.80", default-features = false } +ra-ap-rustc_index = { version = "0.80", default-features = false } +ra-ap-rustc_abi = { version = "0.80", default-features = false } +ra-ap-rustc_pattern_analysis = { version = "0.80", default-features = false } # local crates that aren't published to crates.io. These should not have versions. test-fixture = { path = "./crates/test-fixture" } From 15e8a2691b57a1a486851c4cdfc0342724b1d974 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= Date: Thu, 28 Nov 2024 09:40:14 +0200 Subject: [PATCH 17/17] Fix proc macro test --- .../rust-analyzer/crates/rust-analyzer/tests/slow-tests/main.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/main.rs b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/main.rs index 97c76bf8d1738..c1ca59606379a 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/main.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/main.rs @@ -1085,6 +1085,7 @@ fn resolve_proc_macro() { let sysroot = project_model::Sysroot::discover( &AbsPathBuf::assert_utf8(std::env::current_dir().unwrap()), &Default::default(), + project_model::SysrootQueryMetadata::CargoMetadata, ); let proc_macro_server_path = sysroot.discover_proc_macro_srv().unwrap();