mirror of
https://github.com/rust-lang/rust-analyzer
synced 2025-01-13 21:54:42 +00:00
Auto merge of #133564 - lnicola:sync-from-ra, r=lnicola
Subtree update of `rust-analyzer` r? `@ghost`
This commit is contained in:
commit
8a5d4a3616
25 changed files with 477 additions and 211 deletions
24
Cargo.lock
generated
24
Cargo.lock
generated
|
@ -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",
|
||||
|
|
10
Cargo.toml
10
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" }
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -4790,3 +4790,24 @@ fn allowed3(baz: impl Baz<Assoc = Qux<impl Foo>>) {}
|
|||
"#]],
|
||||
)
|
||||
}
|
||||
|
||||
#[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
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
|
|
@ -116,6 +116,9 @@ impl<'a> AssistContext<'a> {
|
|||
pub(crate) fn find_node_at_offset<N: AstNode>(&self) -> Option<N> {
|
||||
find_node_at_offset(self.source_file.syntax(), self.offset())
|
||||
}
|
||||
pub(crate) fn find_node_at_trimmed_offset<N: AstNode>(&self) -> Option<N> {
|
||||
find_node_at_offset(self.source_file.syntax(), self.trimmed_range.start())
|
||||
}
|
||||
pub(crate) fn find_node_at_range<N: AstNode>(&self) -> Option<N> {
|
||||
find_node_at_range(self.source_file.syntax(), self.trimmed_range)
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use syntax::{
|
||||
ast::{self, edit::AstNodeEdit, make},
|
||||
ast::{self, edit_in_place::Indent, syntax_factory::SyntaxFactory},
|
||||
AstNode,
|
||||
};
|
||||
|
||||
|
@ -39,12 +39,16 @@ pub(crate) fn add_braces(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<(
|
|||
},
|
||||
expr.syntax().text_range(),
|
||||
|builder| {
|
||||
let block_expr = AstNodeEdit::indent(
|
||||
&make::block_expr(None, Some(expr.clone())),
|
||||
AstNodeEdit::indent_level(&expr),
|
||||
);
|
||||
let make = SyntaxFactory::new();
|
||||
let mut editor = builder.make_editor(expr.syntax());
|
||||
|
||||
builder.replace(expr.syntax().text_range(), block_expr.syntax().text());
|
||||
let block_expr = make.block_expr(None, Some(expr.clone()));
|
||||
block_expr.indent(expr.indent_level());
|
||||
|
||||
editor.replace(expr.syntax(), block_expr.syntax());
|
||||
|
||||
editor.add_mappings(make.finish_with_mappings());
|
||||
builder.add_file_edits(ctx.file_id(), editor);
|
||||
},
|
||||
)
|
||||
}
|
||||
|
|
|
@ -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 => ${2:todo!()},$0
|
||||
// }
|
||||
// }
|
||||
// ```
|
||||
|
@ -234,10 +234,11 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>)
|
|||
}
|
||||
}
|
||||
|
||||
let mut first_new_arm = None;
|
||||
let mut added_arms = Vec::new();
|
||||
let mut todo_placeholders = Vec::new();
|
||||
for arm in missing_arms {
|
||||
first_new_arm.get_or_insert_with(|| arm.clone());
|
||||
new_match_arm_list.add_arm(arm);
|
||||
todo_placeholders.push(arm.expr().unwrap());
|
||||
added_arms.push(arm);
|
||||
}
|
||||
|
||||
if needs_catch_all_arm && !has_catch_all_arm {
|
||||
|
@ -248,14 +249,28 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>)
|
|||
make::ext::expr_todo(),
|
||||
)
|
||||
.clone_for_update();
|
||||
first_new_arm.get_or_insert_with(|| arm.clone());
|
||||
todo_placeholders.push(arm.expr().unwrap());
|
||||
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) {
|
||||
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(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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -581,8 +596,8 @@ fn foo(a: bool) {
|
|||
r#"
|
||||
fn foo(a: bool) {
|
||||
match a {
|
||||
$0true => todo!(),
|
||||
false => todo!(),
|
||||
true => ${1:todo!()},
|
||||
false => ${2:todo!()},$0
|
||||
}
|
||||
}
|
||||
"#,
|
||||
|
@ -604,7 +619,7 @@ fn foo(a: bool) {
|
|||
fn foo(a: bool) {
|
||||
match a {
|
||||
true => {}
|
||||
$0false => todo!(),
|
||||
false => ${1:todo!()},$0
|
||||
}
|
||||
}
|
||||
"#,
|
||||
|
@ -654,10 +669,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) => ${4:todo!()},$0
|
||||
}
|
||||
}
|
||||
"#,
|
||||
|
@ -677,8 +692,8 @@ fn foo(a: bool) {
|
|||
r#"
|
||||
fn foo(a: bool) {
|
||||
match [a] {
|
||||
$0[true] => todo!(),
|
||||
[false] => todo!(),
|
||||
[true] => ${1:todo!()},
|
||||
[false] => ${2:todo!()},$0
|
||||
}
|
||||
}
|
||||
"#,
|
||||
|
@ -695,8 +710,8 @@ fn foo(a: bool) {
|
|||
r#"
|
||||
fn foo(a: bool) {
|
||||
match [a,] {
|
||||
$0[true] => todo!(),
|
||||
[false] => todo!(),
|
||||
[true] => ${1:todo!()},
|
||||
[false] => ${2:todo!()},$0
|
||||
}
|
||||
}
|
||||
"#,
|
||||
|
@ -715,9 +730,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] => ${3:todo!()},$0
|
||||
}
|
||||
}
|
||||
"#,
|
||||
|
@ -734,10 +749,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] => ${4:todo!()},$0
|
||||
}
|
||||
}
|
||||
"#,
|
||||
|
@ -759,8 +774,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) => ${2:todo!()},$0
|
||||
}
|
||||
}
|
||||
"#,
|
||||
|
@ -779,9 +794,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) => ${3:todo!()},$0
|
||||
}
|
||||
}
|
||||
"#,
|
||||
|
@ -815,7 +830,7 @@ fn main() {
|
|||
match A::As {
|
||||
A::Bs { x, y: Some(_) } => {}
|
||||
A::Cs(_, Some(_)) => {}
|
||||
$0A::As => todo!(),
|
||||
A::As => ${1:todo!()},$0
|
||||
}
|
||||
}
|
||||
"#,
|
||||
|
@ -838,7 +853,7 @@ fn main() {
|
|||
fn main() {
|
||||
match None {
|
||||
None => {}
|
||||
Some(${0:_}) => todo!(),
|
||||
Some(${1:_}) => ${2:todo!()},$0
|
||||
}
|
||||
}
|
||||
"#,
|
||||
|
@ -862,7 +877,7 @@ enum A { As, Bs, Cs(Option<i32>) }
|
|||
fn main() {
|
||||
match A::As {
|
||||
A::Cs(_) | A::Bs => {}
|
||||
$0A::As => todo!(),
|
||||
A::As => ${1:todo!()},$0
|
||||
}
|
||||
}
|
||||
"#,
|
||||
|
@ -892,8 +907,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 => ${2:todo!()},$0
|
||||
}
|
||||
}
|
||||
"#,
|
||||
|
@ -919,7 +934,7 @@ fn main() {
|
|||
match A::As {
|
||||
A::As(_) => {}
|
||||
a @ A::Bs(_) => {}
|
||||
A::Cs(${0:_}) => todo!(),
|
||||
A::Cs(${1:_}) => ${2:todo!()},$0
|
||||
}
|
||||
}
|
||||
"#,
|
||||
|
@ -945,11 +960,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 } => ${5:todo!()},$0
|
||||
}
|
||||
}
|
||||
"#,
|
||||
|
@ -982,9 +997,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) => ${3:todo!()},$0
|
||||
}
|
||||
}
|
||||
"#,
|
||||
|
@ -1013,10 +1028,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) => ${4:todo!()},$0
|
||||
}
|
||||
}
|
||||
"#,
|
||||
|
@ -1045,10 +1060,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) => ${4:todo!()},$0
|
||||
}
|
||||
}
|
||||
"#,
|
||||
|
@ -1080,9 +1095,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) => ${3:todo!()},$0
|
||||
}
|
||||
}
|
||||
"#,
|
||||
|
@ -1107,9 +1122,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) => ${3:todo!()},$0
|
||||
}
|
||||
}
|
||||
"#,
|
||||
|
@ -1138,7 +1153,7 @@ fn main() {
|
|||
match (a, b) {
|
||||
(Some(_), _) => {}
|
||||
(None, Some(_)) => {}
|
||||
$0(None, None) => todo!(),
|
||||
(None, None) => ${1:todo!()},$0
|
||||
}
|
||||
}
|
||||
"#,
|
||||
|
@ -1203,8 +1218,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,) => ${2:todo!()},$0
|
||||
}
|
||||
}
|
||||
"#,
|
||||
|
@ -1228,7 +1243,7 @@ enum A { As }
|
|||
|
||||
fn foo(a: &A) {
|
||||
match a {
|
||||
$0A::As => todo!(),
|
||||
A::As => ${1:todo!()},$0
|
||||
}
|
||||
}
|
||||
"#,
|
||||
|
@ -1253,7 +1268,7 @@ enum A {
|
|||
|
||||
fn foo(a: &mut A) {
|
||||
match a {
|
||||
$0A::Es { x, y } => todo!(),
|
||||
A::Es { x, y } => ${1:todo!()},$0
|
||||
}
|
||||
}
|
||||
"#,
|
||||
|
@ -1313,8 +1328,8 @@ enum E { X, Y }
|
|||
|
||||
fn main() {
|
||||
match E::X {
|
||||
$0E::X => todo!(),
|
||||
E::Y => todo!(),
|
||||
E::X => ${1:todo!()},
|
||||
E::Y => ${2:todo!()},$0
|
||||
}
|
||||
}
|
||||
"#,
|
||||
|
@ -1360,8 +1375,8 @@ use foo::E::X;
|
|||
|
||||
fn main() {
|
||||
match X {
|
||||
$0X => todo!(),
|
||||
foo::E::Y => todo!(),
|
||||
X => ${1:todo!()},
|
||||
foo::E::Y => ${2:todo!()},$0
|
||||
}
|
||||
}
|
||||
"#,
|
||||
|
@ -1388,7 +1403,7 @@ fn foo(a: A) {
|
|||
match a {
|
||||
// foo bar baz
|
||||
A::One => {}
|
||||
$0A::Two => todo!(),
|
||||
A::Two => ${1:todo!()},$0
|
||||
// This is where the rest should be
|
||||
}
|
||||
}
|
||||
|
@ -1412,8 +1427,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 => ${2:todo!()},$0
|
||||
// foo bar baz
|
||||
}
|
||||
}
|
||||
|
@ -1437,8 +1452,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 => ${2:todo!()},$0
|
||||
}
|
||||
}
|
||||
"#,
|
||||
|
@ -1460,8 +1475,8 @@ fn foo(opt: Option<i32>) {
|
|||
r#"
|
||||
fn foo(opt: Option<i32>) {
|
||||
match opt {
|
||||
Some(${0:_}) => todo!(),
|
||||
None => todo!(),
|
||||
Some(${1:_}) => ${2:todo!()},
|
||||
None => ${3:todo!()},$0
|
||||
}
|
||||
}
|
||||
"#,
|
||||
|
@ -1493,9 +1508,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 => ${3:todo!()},$0
|
||||
});
|
||||
}"#,
|
||||
);
|
||||
|
@ -1530,7 +1545,7 @@ fn foo(t: bool) {
|
|||
fn foo(t: bool) {
|
||||
match t {
|
||||
true => 1 + 2,
|
||||
$0false => todo!(),
|
||||
false => ${1:todo!()},$0
|
||||
}
|
||||
}"#,
|
||||
);
|
||||
|
@ -1550,7 +1565,7 @@ fn foo(t: bool) {
|
|||
fn foo(t: bool) {
|
||||
match t {
|
||||
true => 1 + 2,
|
||||
$0false => todo!(),
|
||||
false => ${1:todo!()},$0
|
||||
}
|
||||
}"#,
|
||||
);
|
||||
|
@ -1571,8 +1586,8 @@ fn foo(t: bool) {
|
|||
fn foo(t: bool) {
|
||||
match t {
|
||||
_ => 1 + 2,
|
||||
$0true => todo!(),
|
||||
false => todo!(),
|
||||
true => ${1:todo!()},
|
||||
false => ${2:todo!()},$0
|
||||
}
|
||||
}"#,
|
||||
);
|
||||
|
@ -1595,8 +1610,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!()},
|
||||
_ => ${2:todo!()},$0
|
||||
}
|
||||
}
|
||||
"#,
|
||||
|
@ -1620,9 +1635,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!()},
|
||||
_ => ${3:todo!()},$0
|
||||
}
|
||||
}
|
||||
"#,
|
||||
|
@ -1646,7 +1661,7 @@ pub enum E { #[doc(hidden)] A, }
|
|||
r#"
|
||||
fn foo(t: ::e::E) {
|
||||
match t {
|
||||
${0:_} => todo!(),
|
||||
${1:_} => ${2:todo!()},$0
|
||||
}
|
||||
}
|
||||
"#,
|
||||
|
@ -1707,7 +1722,7 @@ pub enum E { A, }
|
|||
fn foo(t: ::e::E) {
|
||||
match t {
|
||||
e::E::A => todo!(),
|
||||
${0:_} => todo!(),
|
||||
${1:_} => ${2:todo!()},$0
|
||||
}
|
||||
}
|
||||
"#,
|
||||
|
@ -1732,8 +1747,8 @@ pub enum E { A, }
|
|||
r#"
|
||||
fn foo(t: ::e::E) {
|
||||
match t {
|
||||
$0e::E::A => todo!(),
|
||||
_ => todo!(),
|
||||
e::E::A => ${1:todo!()},
|
||||
_ => ${2:todo!()},$0
|
||||
}
|
||||
}
|
||||
"#,
|
||||
|
@ -1757,8 +1772,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!()},
|
||||
_ => ${2:todo!()},$0
|
||||
}
|
||||
}
|
||||
"#,
|
||||
|
@ -1784,7 +1799,7 @@ pub enum E { A, #[doc(hidden)] B }"#,
|
|||
fn foo(t: ::e::E) {
|
||||
match t {
|
||||
e::E::A => todo!(),
|
||||
${0:_} => todo!(),
|
||||
${1:_} => ${2:todo!()},$0
|
||||
}
|
||||
}
|
||||
"#,
|
||||
|
@ -1809,7 +1824,7 @@ pub enum E { #[doc(hidden)] A, }"#,
|
|||
fn foo(t: ::e::E, b: bool) {
|
||||
match t {
|
||||
_ if b => todo!(),
|
||||
${0:_} => todo!(),
|
||||
${1:_} => ${2:todo!()},$0
|
||||
}
|
||||
}
|
||||
"#,
|
||||
|
@ -1850,8 +1865,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!()},
|
||||
_ => ${2:todo!()},$0
|
||||
}
|
||||
}
|
||||
"#,
|
||||
|
@ -1874,8 +1889,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 => ${2:todo!()},$0
|
||||
}
|
||||
}"#,
|
||||
);
|
||||
|
@ -1899,8 +1914,8 @@ enum E { A, B, }
|
|||
|
||||
fn foo(t: E) {
|
||||
match t {
|
||||
$0E::A => todo!(),
|
||||
E::B => todo!(),
|
||||
E::A => ${1:todo!()},
|
||||
E::B => ${2:todo!()},$0
|
||||
}
|
||||
}"#,
|
||||
);
|
||||
|
@ -1924,8 +1939,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 => ${2:todo!()},$0
|
||||
}
|
||||
}"#,
|
||||
);
|
||||
|
@ -1975,8 +1990,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 } => ${2:todo!()},$0
|
||||
}
|
||||
}"#,
|
||||
)
|
||||
|
@ -2013,8 +2028,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) => ${2:todo!()},$0
|
||||
}
|
||||
}
|
||||
"#,
|
||||
|
@ -2051,8 +2066,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) => ${2:todo!()},$0
|
||||
}
|
||||
}
|
||||
"#,
|
||||
|
|
|
@ -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::<ast::MatchArm>()?;
|
||||
let current_arm = ctx.find_node_at_trimmed_offset::<ast::MatchArm>()?;
|
||||
// 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(
|
||||
|
|
|
@ -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::<ast::Impl>()?;
|
||||
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::<Vec<_>>();
|
||||
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);
|
||||
},
|
||||
)
|
||||
}
|
||||
|
|
|
@ -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 => ${2:todo!()},$0
|
||||
}
|
||||
}
|
||||
"#####,
|
||||
|
|
|
@ -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<String>,
|
||||
/// Sysroot loading behavior
|
||||
pub sysroot: Option<RustLibSource>,
|
||||
/// How to query metadata for the sysroot crate.
|
||||
pub sysroot_query_metadata: SysrootQueryMetadata,
|
||||
pub sysroot_src: Option<AbsPathBuf>,
|
||||
/// rustc private crate source
|
||||
pub rustc_source: Option<RustLibSource>,
|
||||
|
|
|
@ -240,3 +240,10 @@ fn parse_cfg(s: &str) -> Result<cfg::CfgAtom, String> {
|
|||
};
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
|
||||
pub enum SysrootQueryMetadata {
|
||||
#[default]
|
||||
CargoMetadata,
|
||||
None,
|
||||
}
|
||||
|
|
|
@ -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<String, String>) -> Sysroot {
|
||||
pub fn discover(
|
||||
dir: &AbsPath,
|
||||
extra_env: &FxHashMap<String, String>,
|
||||
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<String, String>,
|
||||
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<ManifestPath> {
|
||||
|
@ -186,15 +202,20 @@ impl Sysroot {
|
|||
})
|
||||
}
|
||||
|
||||
pub fn load(sysroot_dir: Option<AbsPathBuf>, sysroot_src_dir: Option<AbsPathBuf>) -> Sysroot {
|
||||
Self::load_core_check(sysroot_dir.map(Ok), sysroot_src_dir.map(Ok))
|
||||
pub fn load(
|
||||
sysroot_dir: Option<AbsPathBuf>,
|
||||
sysroot_src_dir: Option<AbsPathBuf>,
|
||||
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<Result<AbsPathBuf, anyhow::Error>>,
|
||||
sysroot_src_dir: Option<Result<AbsPathBuf, anyhow::Error>>,
|
||||
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<Result<AbsPathBuf, anyhow::Error>>,
|
||||
sysroot_src_dir: Option<Result<AbsPathBuf, anyhow::Error>>,
|
||||
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}");
|
||||
|
@ -444,13 +469,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`"
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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<String, String>,
|
||||
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<ProjectWorkspace> {
|
||||
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(),
|
||||
};
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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<String>,
|
||||
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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -558,6 +558,9 @@ config_data! {
|
|||
///
|
||||
/// This option does not take effect until rust-analyzer is restarted.
|
||||
cargo_sysroot: Option<String> = 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})"),
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
|
|
@ -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`)::
|
||||
+
|
||||
--
|
||||
|
|
|
@ -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": {
|
||||
|
|
|
@ -1 +1 @@
|
|||
145f9cf95de1fbde3fa11e98461310e0373253e6
|
||||
f005c7437def424a1c43cbc380352a58d8ac920b
|
||||
|
|
Loading…
Reference in a new issue