Auto merge of #14128 - Veykril:parser, r=Veykril

internal: Improve parser recovery for delimited lists

Closes https://github.com/rust-lang/rust-analyzer/issues/11188, https://github.com/rust-lang/rust-analyzer/issues/10410, https://github.com/rust-lang/rust-analyzer/issues/10173

Should probably be merged after the stable release as this might get the parser stuck if I missed something
This commit is contained in:
bors 2023-02-14 12:59:39 +00:00
commit 44568007d1
33 changed files with 817 additions and 367 deletions

View file

@ -668,8 +668,15 @@ fn classify_name_ref(
};
let after_if_expr = |node: SyntaxNode| {
let prev_expr = (|| {
let node = match node.parent().and_then(ast::ExprStmt::cast) {
Some(stmt) => stmt.syntax().clone(),
None => node,
};
let prev_sibling = non_trivia_sibling(node.into(), Direction::Prev)?.into_node()?;
ast::ExprStmt::cast(prev_sibling)?.expr()
ast::ExprStmt::cast(prev_sibling.clone())
.and_then(|it| it.expr())
.or_else(|| ast::Expr::cast(prev_sibling))
})();
matches!(prev_expr, Some(ast::Expr::IfExpr(_)))
};

View file

@ -745,3 +745,255 @@ fn return_value_no_block() {
r#"fn f() -> i32 { match () { () => return $0 } }"#,
);
}
#[test]
fn else_completion_after_if() {
check_empty(
r#"
fn foo() { if foo {} $0 }
"#,
expect![[r#"
fn foo() fn()
bt u32
kw const
kw crate::
kw else
kw else if
kw enum
kw extern
kw false
kw fn
kw for
kw if
kw if let
kw impl
kw let
kw loop
kw match
kw mod
kw return
kw self::
kw static
kw struct
kw trait
kw true
kw type
kw union
kw unsafe
kw use
kw while
kw while let
sn macro_rules
sn pd
sn ppd
"#]],
);
check_empty(
r#"
fn foo() { if foo {} el$0 }
"#,
expect![[r#"
fn foo() fn()
bt u32
kw const
kw crate::
kw else
kw else if
kw enum
kw extern
kw false
kw fn
kw for
kw if
kw if let
kw impl
kw let
kw loop
kw match
kw mod
kw return
kw self::
kw static
kw struct
kw trait
kw true
kw type
kw union
kw unsafe
kw use
kw while
kw while let
sn macro_rules
sn pd
sn ppd
"#]],
);
check_empty(
r#"
fn foo() { bar(if foo {} $0) }
"#,
expect![[r#"
fn foo() fn()
bt u32
kw crate::
kw else
kw else if
kw false
kw for
kw if
kw if let
kw loop
kw match
kw return
kw self::
kw true
kw unsafe
kw while
kw while let
"#]],
);
check_empty(
r#"
fn foo() { bar(if foo {} el$0) }
"#,
expect![[r#"
fn foo() fn()
bt u32
kw crate::
kw else
kw else if
kw false
kw for
kw if
kw if let
kw loop
kw match
kw return
kw self::
kw true
kw unsafe
kw while
kw while let
"#]],
);
check_empty(
r#"
fn foo() { if foo {} $0 let x = 92; }
"#,
expect![[r#"
fn foo() fn()
bt u32
kw const
kw crate::
kw else
kw else if
kw enum
kw extern
kw false
kw fn
kw for
kw if
kw if let
kw impl
kw let
kw loop
kw match
kw mod
kw return
kw self::
kw static
kw struct
kw trait
kw true
kw type
kw union
kw unsafe
kw use
kw while
kw while let
sn macro_rules
sn pd
sn ppd
"#]],
);
check_empty(
r#"
fn foo() { if foo {} el$0 let x = 92; }
"#,
expect![[r#"
fn foo() fn()
bt u32
kw const
kw crate::
kw else
kw else if
kw enum
kw extern
kw false
kw fn
kw for
kw if
kw if let
kw impl
kw let
kw loop
kw match
kw mod
kw return
kw self::
kw static
kw struct
kw trait
kw true
kw type
kw union
kw unsafe
kw use
kw while
kw while let
sn macro_rules
sn pd
sn ppd
"#]],
);
check_empty(
r#"
fn foo() { if foo {} el$0 { let x = 92; } }
"#,
expect![[r#"
fn foo() fn()
bt u32
kw const
kw crate::
kw else
kw else if
kw enum
kw extern
kw false
kw fn
kw for
kw if
kw if let
kw impl
kw let
kw loop
kw match
kw mod
kw return
kw self::
kw static
kw struct
kw trait
kw true
kw type
kw union
kw unsafe
kw use
kw while
kw while let
sn macro_rules
sn pd
sn ppd
"#]],
);
}

View file

@ -2,10 +2,17 @@
use expect_test::{expect, Expect};
use crate::tests::{check_edit, completion_list_no_kw, completion_list_with_trigger_character};
use crate::tests::{
check_edit, completion_list, completion_list_no_kw, completion_list_with_trigger_character,
};
fn check_no_kw(ra_fixture: &str, expect: Expect) {
let actual = completion_list_no_kw(ra_fixture);
expect.assert_eq(&actual)
}
fn check(ra_fixture: &str, expect: Expect) {
let actual = completion_list_no_kw(ra_fixture);
let actual = completion_list(ra_fixture);
expect.assert_eq(&actual)
}
@ -59,7 +66,7 @@ fn _alpha() {}
#[test]
fn completes_prelude() {
check(
check_no_kw(
r#"
//- /main.rs edition:2018 crate:main deps:std
fn foo() { let x: $0 }
@ -81,7 +88,7 @@ pub mod prelude {
#[test]
fn completes_prelude_macros() {
check(
check_no_kw(
r#"
//- /main.rs edition:2018 crate:main deps:std
fn f() {$0}
@ -110,7 +117,7 @@ mod macros {
#[test]
fn completes_std_prelude_if_core_is_defined() {
check(
check_no_kw(
r#"
//- /main.rs crate:main deps:core,std
fn foo() { let x: $0 }
@ -140,7 +147,7 @@ pub mod prelude {
#[test]
fn respects_doc_hidden() {
check(
check_no_kw(
r#"
//- /lib.rs crate:lib deps:std
fn f() {
@ -168,7 +175,7 @@ pub mod prelude {
#[test]
fn respects_doc_hidden_in_assoc_item_list() {
check(
check_no_kw(
r#"
//- /lib.rs crate:lib deps:std
struct S;
@ -195,7 +202,7 @@ pub mod prelude {
#[test]
fn associated_item_visibility() {
check(
check_no_kw(
r#"
//- /lib.rs crate:lib new_source_root:library
pub struct S;
@ -222,7 +229,7 @@ fn foo() { let _ = lib::S::$0 }
#[test]
fn completes_union_associated_method() {
check(
check_no_kw(
r#"
union U {};
impl U { fn m() { } }
@ -237,7 +244,7 @@ fn foo() { let _ = U::$0 }
#[test]
fn completes_trait_associated_method_1() {
check(
check_no_kw(
r#"
trait Trait { fn m(); }
@ -251,7 +258,7 @@ fn foo() { let _ = Trait::$0 }
#[test]
fn completes_trait_associated_method_2() {
check(
check_no_kw(
r#"
trait Trait { fn m(); }
@ -268,7 +275,7 @@ fn foo() { let _ = S::$0 }
#[test]
fn completes_trait_associated_method_3() {
check(
check_no_kw(
r#"
trait Trait { fn m(); }
@ -285,7 +292,7 @@ fn foo() { let _ = <S as Trait>::$0 }
#[test]
fn completes_ty_param_assoc_ty() {
check(
check_no_kw(
r#"
trait Super {
type Ty;
@ -318,7 +325,7 @@ fn foo<T: Sub>() { T::$0 }
#[test]
fn completes_self_param_assoc_ty() {
check(
check_no_kw(
r#"
trait Super {
type Ty;
@ -358,7 +365,7 @@ impl<T> Sub for Wrap<T> {
#[test]
fn completes_type_alias() {
check(
check_no_kw(
r#"
struct S;
impl S { fn foo() {} }
@ -376,7 +383,7 @@ fn main() { T::$0; }
#[test]
fn completes_qualified_macros() {
check(
check_no_kw(
r#"
#[macro_export]
macro_rules! foo { () => {} }
@ -392,7 +399,7 @@ fn main() { let _ = crate::$0 }
#[test]
fn does_not_complete_non_fn_macros() {
check(
check_no_kw(
r#"
mod m {
#[rustc_builtin_macro]
@ -403,7 +410,7 @@ fn f() {m::$0}
"#,
expect![[r#""#]],
);
check(
check_no_kw(
r#"
mod m {
#[rustc_builtin_macro]
@ -418,7 +425,7 @@ fn f() {m::$0}
#[test]
fn completes_reexported_items_under_correct_name() {
check(
check_no_kw(
r#"
fn foo() { self::m::$0 }
@ -475,7 +482,7 @@ mod p {
#[test]
fn completes_in_simple_macro_call() {
check(
check_no_kw(
r#"
macro_rules! m { ($e:expr) => { $e } }
fn main() { m!(self::f$0); }
@ -490,7 +497,7 @@ fn foo() {}
#[test]
fn function_mod_share_name() {
check(
check_no_kw(
r#"
fn foo() { self::m::$0 }
@ -508,7 +515,7 @@ mod m {
#[test]
fn completes_hashmap_new() {
check(
check_no_kw(
r#"
struct RandomState;
struct HashMap<K, V, S = RandomState> {}
@ -529,7 +536,7 @@ fn foo() {
#[test]
fn completes_variant_through_self() {
cov_mark::check!(completes_variant_through_self);
check(
check_no_kw(
r#"
enum Foo {
Bar,
@ -552,7 +559,7 @@ impl Foo {
#[test]
fn completes_non_exhaustive_variant_within_the_defining_crate() {
check(
check_no_kw(
r#"
enum Foo {
#[non_exhaustive]
@ -570,7 +577,7 @@ fn foo(self) {
"#]],
);
check(
check_no_kw(
r#"
//- /main.rs crate:main deps:e
fn foo(self) {
@ -593,7 +600,7 @@ enum Foo {
#[test]
fn completes_primitive_assoc_const() {
cov_mark::check!(completes_primitive_assoc_const);
check(
check_no_kw(
r#"
//- /lib.rs crate:lib deps:core
fn f() {
@ -618,7 +625,7 @@ impl u8 {
#[test]
fn completes_variant_through_alias() {
cov_mark::check!(completes_variant_through_alias);
check(
check_no_kw(
r#"
enum Foo {
Bar
@ -636,7 +643,7 @@ fn main() {
#[test]
fn respects_doc_hidden2() {
check(
check_no_kw(
r#"
//- /lib.rs crate:lib deps:dep
fn f() {
@ -665,7 +672,7 @@ pub mod m {}
#[test]
fn type_anchor_empty() {
check(
check_no_kw(
r#"
trait Foo {
fn foo() -> Self;
@ -688,7 +695,7 @@ fn bar() -> Bar {
#[test]
fn type_anchor_type() {
check(
check_no_kw(
r#"
trait Foo {
fn foo() -> Self;
@ -715,7 +722,7 @@ fn bar() -> Bar {
#[test]
fn type_anchor_type_trait() {
check(
check_no_kw(
r#"
trait Foo {
fn foo() -> Self;
@ -741,7 +748,7 @@ fn bar() -> Bar {
#[test]
fn completes_fn_in_pub_trait_generated_by_macro() {
check(
check_no_kw(
r#"
mod other_mod {
macro_rules! make_method {
@ -775,7 +782,7 @@ fn main() {
#[test]
fn completes_fn_in_pub_trait_generated_by_recursive_macro() {
check(
check_no_kw(
r#"
mod other_mod {
macro_rules! make_method {
@ -815,7 +822,7 @@ fn main() {
#[test]
fn completes_const_in_pub_trait_generated_by_macro() {
check(
check_no_kw(
r#"
mod other_mod {
macro_rules! make_const {
@ -847,7 +854,7 @@ fn main() {
#[test]
fn completes_locals_from_macros() {
check(
check_no_kw(
r#"
macro_rules! x {
@ -875,7 +882,7 @@ fn main() {
#[test]
fn regression_12644() {
check(
check_no_kw(
r#"
macro_rules! __rust_force_expr {
($e:expr) => {
@ -974,7 +981,7 @@ fn foo { crate:::$0 }
"#,
expect![""],
);
check(
check_no_kw(
r#"
fn foo { crate::::$0 }
"#,