internal: scalable module structure for fixits

This commit is contained in:
Aleksey Kladov 2021-05-17 12:04:17 +03:00
parent db8fbb99ce
commit fa7fc0e5cb
9 changed files with 695 additions and 769 deletions

View file

@ -375,7 +375,7 @@ mod tests {
assert_eq!(diagnostics.len(), 0, "unexpected diagnostics:\n{:#?}", diagnostics);
}
fn check_expect(ra_fixture: &str, expect: Expect) {
pub(crate) fn check_expect(ra_fixture: &str, expect: Expect) {
let (analysis, file_id) = fixture::file(ra_fixture);
let diagnostics = analysis
.diagnostics(&DiagnosticsConfig::default(), AssistResolveStrategy::All, file_id)
@ -383,374 +383,6 @@ mod tests {
expect.assert_debug_eq(&diagnostics)
}
#[test]
fn test_wrap_return_type_option() {
check_fix(
r#"
//- /main.rs crate:main deps:core
use core::option::Option::{self, Some, None};
fn div(x: i32, y: i32) -> Option<i32> {
if y == 0 {
return None;
}
x / y$0
}
//- /core/lib.rs crate:core
pub mod result {
pub enum Result<T, E> { Ok(T), Err(E) }
}
pub mod option {
pub enum Option<T> { Some(T), None }
}
"#,
r#"
use core::option::Option::{self, Some, None};
fn div(x: i32, y: i32) -> Option<i32> {
if y == 0 {
return None;
}
Some(x / y)
}
"#,
);
}
#[test]
fn test_wrap_return_type() {
check_fix(
r#"
//- /main.rs crate:main deps:core
use core::result::Result::{self, Ok, Err};
fn div(x: i32, y: i32) -> Result<i32, ()> {
if y == 0 {
return Err(());
}
x / y$0
}
//- /core/lib.rs crate:core
pub mod result {
pub enum Result<T, E> { Ok(T), Err(E) }
}
pub mod option {
pub enum Option<T> { Some(T), None }
}
"#,
r#"
use core::result::Result::{self, Ok, Err};
fn div(x: i32, y: i32) -> Result<i32, ()> {
if y == 0 {
return Err(());
}
Ok(x / y)
}
"#,
);
}
#[test]
fn test_wrap_return_type_handles_generic_functions() {
check_fix(
r#"
//- /main.rs crate:main deps:core
use core::result::Result::{self, Ok, Err};
fn div<T>(x: T) -> Result<T, i32> {
if x == 0 {
return Err(7);
}
$0x
}
//- /core/lib.rs crate:core
pub mod result {
pub enum Result<T, E> { Ok(T), Err(E) }
}
pub mod option {
pub enum Option<T> { Some(T), None }
}
"#,
r#"
use core::result::Result::{self, Ok, Err};
fn div<T>(x: T) -> Result<T, i32> {
if x == 0 {
return Err(7);
}
Ok(x)
}
"#,
);
}
#[test]
fn test_wrap_return_type_handles_type_aliases() {
check_fix(
r#"
//- /main.rs crate:main deps:core
use core::result::Result::{self, Ok, Err};
type MyResult<T> = Result<T, ()>;
fn div(x: i32, y: i32) -> MyResult<i32> {
if y == 0 {
return Err(());
}
x $0/ y
}
//- /core/lib.rs crate:core
pub mod result {
pub enum Result<T, E> { Ok(T), Err(E) }
}
pub mod option {
pub enum Option<T> { Some(T), None }
}
"#,
r#"
use core::result::Result::{self, Ok, Err};
type MyResult<T> = Result<T, ()>;
fn div(x: i32, y: i32) -> MyResult<i32> {
if y == 0 {
return Err(());
}
Ok(x / y)
}
"#,
);
}
#[test]
fn test_wrap_return_type_not_applicable_when_expr_type_does_not_match_ok_type() {
check_no_diagnostics(
r#"
//- /main.rs crate:main deps:core
use core::result::Result::{self, Ok, Err};
fn foo() -> Result<(), i32> { 0 }
//- /core/lib.rs crate:core
pub mod result {
pub enum Result<T, E> { Ok(T), Err(E) }
}
pub mod option {
pub enum Option<T> { Some(T), None }
}
"#,
);
}
#[test]
fn test_wrap_return_type_not_applicable_when_return_type_is_not_result_or_option() {
check_no_diagnostics(
r#"
//- /main.rs crate:main deps:core
use core::result::Result::{self, Ok, Err};
enum SomeOtherEnum { Ok(i32), Err(String) }
fn foo() -> SomeOtherEnum { 0 }
//- /core/lib.rs crate:core
pub mod result {
pub enum Result<T, E> { Ok(T), Err(E) }
}
pub mod option {
pub enum Option<T> { Some(T), None }
}
"#,
);
}
#[test]
fn test_fill_struct_fields_empty() {
check_fix(
r#"
struct TestStruct { one: i32, two: i64 }
fn test_fn() {
let s = TestStruct {$0};
}
"#,
r#"
struct TestStruct { one: i32, two: i64 }
fn test_fn() {
let s = TestStruct { one: (), two: () };
}
"#,
);
}
#[test]
fn test_fill_struct_fields_self() {
check_fix(
r#"
struct TestStruct { one: i32 }
impl TestStruct {
fn test_fn() { let s = Self {$0}; }
}
"#,
r#"
struct TestStruct { one: i32 }
impl TestStruct {
fn test_fn() { let s = Self { one: () }; }
}
"#,
);
}
#[test]
fn test_fill_struct_fields_enum() {
check_fix(
r#"
enum Expr {
Bin { lhs: Box<Expr>, rhs: Box<Expr> }
}
impl Expr {
fn new_bin(lhs: Box<Expr>, rhs: Box<Expr>) -> Expr {
Expr::Bin {$0 }
}
}
"#,
r#"
enum Expr {
Bin { lhs: Box<Expr>, rhs: Box<Expr> }
}
impl Expr {
fn new_bin(lhs: Box<Expr>, rhs: Box<Expr>) -> Expr {
Expr::Bin { lhs: (), rhs: () }
}
}
"#,
);
}
#[test]
fn test_fill_struct_fields_partial() {
check_fix(
r#"
struct TestStruct { one: i32, two: i64 }
fn test_fn() {
let s = TestStruct{ two: 2$0 };
}
"#,
r"
struct TestStruct { one: i32, two: i64 }
fn test_fn() {
let s = TestStruct{ two: 2, one: () };
}
",
);
}
#[test]
fn test_fill_struct_fields_raw_ident() {
check_fix(
r#"
struct TestStruct { r#type: u8 }
fn test_fn() {
TestStruct { $0 };
}
"#,
r"
struct TestStruct { r#type: u8 }
fn test_fn() {
TestStruct { r#type: () };
}
",
);
}
#[test]
fn test_fill_struct_fields_no_diagnostic() {
check_no_diagnostics(
r"
struct TestStruct { one: i32, two: i64 }
fn test_fn() {
let one = 1;
let s = TestStruct{ one, two: 2 };
}
",
);
}
#[test]
fn test_fill_struct_fields_no_diagnostic_on_spread() {
check_no_diagnostics(
r"
struct TestStruct { one: i32, two: i64 }
fn test_fn() {
let one = 1;
let s = TestStruct{ ..a };
}
",
);
}
#[test]
fn test_unresolved_module_diagnostic() {
check_expect(
r#"mod foo;"#,
expect![[r#"
[
Diagnostic {
message: "unresolved module",
range: 0..8,
severity: Error,
fix: Some(
Assist {
id: AssistId(
"create_module",
QuickFix,
),
label: "Create module",
group: None,
target: 0..8,
source_change: Some(
SourceChange {
source_file_edits: {},
file_system_edits: [
CreateFile {
dst: AnchoredPathBuf {
anchor: FileId(
0,
),
path: "foo.rs",
},
initial_contents: "",
},
],
is_snippet: false,
},
),
},
),
unused: false,
code: Some(
DiagnosticCode(
"unresolved-module",
),
),
},
]
"#]],
);
}
#[test]
fn test_unresolved_macro_range() {
check_expect(
@ -890,53 +522,6 @@ mod a {
);
}
#[test]
fn test_add_field_from_usage() {
check_fix(
r"
fn main() {
Foo { bar: 3, baz$0: false};
}
struct Foo {
bar: i32
}
",
r"
fn main() {
Foo { bar: 3, baz: false};
}
struct Foo {
bar: i32,
baz: bool
}
",
)
}
#[test]
fn test_add_field_in_other_file_from_usage() {
check_fix(
r#"
//- /main.rs
mod foo;
fn main() {
foo::Foo { bar: 3, $0baz: false};
}
//- /foo.rs
struct Foo {
bar: i32
}
"#,
r#"
struct Foo {
bar: i32,
pub(crate) baz: bool
}
"#,
)
}
#[test]
fn test_disabled_diagnostics() {
let mut config = DiagnosticsConfig::default();
@ -954,120 +539,6 @@ struct Foo {
assert!(!diagnostics.is_empty());
}
#[test]
fn test_rename_incorrect_case() {
check_fix(
r#"
pub struct test_struct$0 { one: i32 }
pub fn some_fn(val: test_struct) -> test_struct {
test_struct { one: val.one + 1 }
}
"#,
r#"
pub struct TestStruct { one: i32 }
pub fn some_fn(val: TestStruct) -> TestStruct {
TestStruct { one: val.one + 1 }
}
"#,
);
check_fix(
r#"
pub fn some_fn(NonSnakeCase$0: u8) -> u8 {
NonSnakeCase
}
"#,
r#"
pub fn some_fn(non_snake_case: u8) -> u8 {
non_snake_case
}
"#,
);
check_fix(
r#"
pub fn SomeFn$0(val: u8) -> u8 {
if val != 0 { SomeFn(val - 1) } else { val }
}
"#,
r#"
pub fn some_fn(val: u8) -> u8 {
if val != 0 { some_fn(val - 1) } else { val }
}
"#,
);
check_fix(
r#"
fn some_fn() {
let whatAWeird_Formatting$0 = 10;
another_func(whatAWeird_Formatting);
}
"#,
r#"
fn some_fn() {
let what_a_weird_formatting = 10;
another_func(what_a_weird_formatting);
}
"#,
);
}
#[test]
fn test_uppercase_const_no_diagnostics() {
check_no_diagnostics(
r#"
fn foo() {
const ANOTHER_ITEM$0: &str = "some_item";
}
"#,
);
}
#[test]
fn test_rename_incorrect_case_struct_method() {
check_fix(
r#"
pub struct TestStruct;
impl TestStruct {
pub fn SomeFn$0() -> TestStruct {
TestStruct
}
}
"#,
r#"
pub struct TestStruct;
impl TestStruct {
pub fn some_fn() -> TestStruct {
TestStruct
}
}
"#,
);
}
#[test]
fn test_single_incorrect_case_diagnostic_in_function_name_issue_6970() {
let input = r#"fn FOO$0() {}"#;
let expected = r#"fn foo() {}"#;
let (analysis, file_position) = fixture::position(input);
let diagnostics = analysis
.diagnostics(
&DiagnosticsConfig::default(),
AssistResolveStrategy::All,
file_position.file_id,
)
.unwrap();
assert_eq!(diagnostics.len(), 1);
check_fix(input, expected);
}
#[test]
fn unlinked_file_prepend_first_item() {
cov_mark::check!(unlinked_file_prepend_before_first_item);