Extract tests module to file in ide_db crate
This commit is contained in:
parent
5a1306a436
commit
f486640682
@ -228,529 +228,4 @@ fn arg_list(&self) -> Option<ast::ArgList> {
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::RootDatabase;
|
||||
use base_db::{fixture::ChangeFixture, FilePosition};
|
||||
use expect_test::{expect, Expect};
|
||||
use test_utils::{mark, RangeOrOffset};
|
||||
|
||||
/// Creates analysis from a multi-file fixture, returns positions marked with <|>.
|
||||
pub(crate) fn position(ra_fixture: &str) -> (RootDatabase, FilePosition) {
|
||||
let change_fixture = ChangeFixture::parse(ra_fixture);
|
||||
let mut database = RootDatabase::default();
|
||||
database.apply_change(change_fixture.change);
|
||||
let (file_id, range_or_offset) =
|
||||
change_fixture.file_position.expect("expected a marker (<|>)");
|
||||
let offset = match range_or_offset {
|
||||
RangeOrOffset::Range(_) => panic!(),
|
||||
RangeOrOffset::Offset(it) => it,
|
||||
};
|
||||
(database, FilePosition { file_id, offset })
|
||||
}
|
||||
|
||||
fn check(ra_fixture: &str, expect: Expect) {
|
||||
let (db, position) = position(ra_fixture);
|
||||
let call_info = crate::call_info::call_info(&db, position);
|
||||
let actual = match call_info {
|
||||
Some(call_info) => {
|
||||
let docs = match &call_info.doc {
|
||||
None => "".to_string(),
|
||||
Some(docs) => format!("{}\n------\n", docs.as_str()),
|
||||
};
|
||||
let params = call_info
|
||||
.parameter_labels()
|
||||
.enumerate()
|
||||
.map(|(i, param)| {
|
||||
if Some(i) == call_info.active_parameter {
|
||||
format!("<{}>", param)
|
||||
} else {
|
||||
param.to_string()
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
.join(", ");
|
||||
format!("{}{}\n({})\n", docs, call_info.signature, params)
|
||||
}
|
||||
None => String::new(),
|
||||
};
|
||||
expect.assert_eq(&actual);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fn_signature_two_args() {
|
||||
check(
|
||||
r#"
|
||||
fn foo(x: u32, y: u32) -> u32 {x + y}
|
||||
fn bar() { foo(<|>3, ); }
|
||||
"#,
|
||||
expect![[r#"
|
||||
fn foo(x: u32, y: u32) -> u32
|
||||
(<x: u32>, y: u32)
|
||||
"#]],
|
||||
);
|
||||
check(
|
||||
r#"
|
||||
fn foo(x: u32, y: u32) -> u32 {x + y}
|
||||
fn bar() { foo(3<|>, ); }
|
||||
"#,
|
||||
expect![[r#"
|
||||
fn foo(x: u32, y: u32) -> u32
|
||||
(<x: u32>, y: u32)
|
||||
"#]],
|
||||
);
|
||||
check(
|
||||
r#"
|
||||
fn foo(x: u32, y: u32) -> u32 {x + y}
|
||||
fn bar() { foo(3,<|> ); }
|
||||
"#,
|
||||
expect![[r#"
|
||||
fn foo(x: u32, y: u32) -> u32
|
||||
(x: u32, <y: u32>)
|
||||
"#]],
|
||||
);
|
||||
check(
|
||||
r#"
|
||||
fn foo(x: u32, y: u32) -> u32 {x + y}
|
||||
fn bar() { foo(3, <|>); }
|
||||
"#,
|
||||
expect![[r#"
|
||||
fn foo(x: u32, y: u32) -> u32
|
||||
(x: u32, <y: u32>)
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fn_signature_two_args_empty() {
|
||||
check(
|
||||
r#"
|
||||
fn foo(x: u32, y: u32) -> u32 {x + y}
|
||||
fn bar() { foo(<|>); }
|
||||
"#,
|
||||
expect![[r#"
|
||||
fn foo(x: u32, y: u32) -> u32
|
||||
(<x: u32>, y: u32)
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fn_signature_two_args_first_generics() {
|
||||
check(
|
||||
r#"
|
||||
fn foo<T, U: Copy + Display>(x: T, y: U) -> u32
|
||||
where T: Copy + Display, U: Debug
|
||||
{ x + y }
|
||||
|
||||
fn bar() { foo(<|>3, ); }
|
||||
"#,
|
||||
expect![[r#"
|
||||
fn foo(x: i32, y: {unknown}) -> u32
|
||||
(<x: i32>, y: {unknown})
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fn_signature_no_params() {
|
||||
check(
|
||||
r#"
|
||||
fn foo<T>() -> T where T: Copy + Display {}
|
||||
fn bar() { foo(<|>); }
|
||||
"#,
|
||||
expect![[r#"
|
||||
fn foo() -> {unknown}
|
||||
()
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fn_signature_for_impl() {
|
||||
check(
|
||||
r#"
|
||||
struct F;
|
||||
impl F { pub fn new() { } }
|
||||
fn bar() {
|
||||
let _ : F = F::new(<|>);
|
||||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
fn new()
|
||||
()
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fn_signature_for_method_self() {
|
||||
check(
|
||||
r#"
|
||||
struct S;
|
||||
impl S { pub fn do_it(&self) {} }
|
||||
|
||||
fn bar() {
|
||||
let s: S = S;
|
||||
s.do_it(<|>);
|
||||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
fn do_it(&self)
|
||||
()
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fn_signature_for_method_with_arg() {
|
||||
check(
|
||||
r#"
|
||||
struct S;
|
||||
impl S {
|
||||
fn foo(&self, x: i32) {}
|
||||
}
|
||||
|
||||
fn main() { S.foo(<|>); }
|
||||
"#,
|
||||
expect![[r#"
|
||||
fn foo(&self, x: i32)
|
||||
(<x: i32>)
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fn_signature_for_method_with_arg_as_assoc_fn() {
|
||||
check(
|
||||
r#"
|
||||
struct S;
|
||||
impl S {
|
||||
fn foo(&self, x: i32) {}
|
||||
}
|
||||
|
||||
fn main() { S::foo(<|>); }
|
||||
"#,
|
||||
expect![[r#"
|
||||
fn foo(self: &S, x: i32)
|
||||
(<self: &S>, x: i32)
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fn_signature_with_docs_simple() {
|
||||
check(
|
||||
r#"
|
||||
/// test
|
||||
// non-doc-comment
|
||||
fn foo(j: u32) -> u32 {
|
||||
j
|
||||
}
|
||||
|
||||
fn bar() {
|
||||
let _ = foo(<|>);
|
||||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
test
|
||||
------
|
||||
fn foo(j: u32) -> u32
|
||||
(<j: u32>)
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fn_signature_with_docs() {
|
||||
check(
|
||||
r#"
|
||||
/// Adds one to the number given.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// let five = 5;
|
||||
///
|
||||
/// assert_eq!(6, my_crate::add_one(5));
|
||||
/// ```
|
||||
pub fn add_one(x: i32) -> i32 {
|
||||
x + 1
|
||||
}
|
||||
|
||||
pub fn do() {
|
||||
add_one(<|>
|
||||
}"#,
|
||||
expect![[r##"
|
||||
Adds one to the number given.
|
||||
|
||||
# Examples
|
||||
|
||||
```
|
||||
let five = 5;
|
||||
|
||||
assert_eq!(6, my_crate::add_one(5));
|
||||
```
|
||||
------
|
||||
fn add_one(x: i32) -> i32
|
||||
(<x: i32>)
|
||||
"##]],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fn_signature_with_docs_impl() {
|
||||
check(
|
||||
r#"
|
||||
struct addr;
|
||||
impl addr {
|
||||
/// Adds one to the number given.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// let five = 5;
|
||||
///
|
||||
/// assert_eq!(6, my_crate::add_one(5));
|
||||
/// ```
|
||||
pub fn add_one(x: i32) -> i32 {
|
||||
x + 1
|
||||
}
|
||||
}
|
||||
|
||||
pub fn do_it() {
|
||||
addr {};
|
||||
addr::add_one(<|>);
|
||||
}
|
||||
"#,
|
||||
expect![[r##"
|
||||
Adds one to the number given.
|
||||
|
||||
# Examples
|
||||
|
||||
```
|
||||
let five = 5;
|
||||
|
||||
assert_eq!(6, my_crate::add_one(5));
|
||||
```
|
||||
------
|
||||
fn add_one(x: i32) -> i32
|
||||
(<x: i32>)
|
||||
"##]],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fn_signature_with_docs_from_actix() {
|
||||
check(
|
||||
r#"
|
||||
struct WriteHandler<E>;
|
||||
|
||||
impl<E> WriteHandler<E> {
|
||||
/// Method is called when writer emits error.
|
||||
///
|
||||
/// If this method returns `ErrorAction::Continue` writer processing
|
||||
/// continues otherwise stream processing stops.
|
||||
fn error(&mut self, err: E, ctx: &mut Self::Context) -> Running {
|
||||
Running::Stop
|
||||
}
|
||||
|
||||
/// Method is called when writer finishes.
|
||||
///
|
||||
/// By default this method stops actor's `Context`.
|
||||
fn finished(&mut self, ctx: &mut Self::Context) {
|
||||
ctx.stop()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn foo(mut r: WriteHandler<()>) {
|
||||
r.finished(<|>);
|
||||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
Method is called when writer finishes.
|
||||
|
||||
By default this method stops actor's `Context`.
|
||||
------
|
||||
fn finished(&mut self, ctx: &mut {unknown})
|
||||
(<ctx: &mut {unknown}>)
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn call_info_bad_offset() {
|
||||
mark::check!(call_info_bad_offset);
|
||||
check(
|
||||
r#"
|
||||
fn foo(x: u32, y: u32) -> u32 {x + y}
|
||||
fn bar() { foo <|> (3, ); }
|
||||
"#,
|
||||
expect![[""]],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_nested_method_in_lambda() {
|
||||
check(
|
||||
r#"
|
||||
struct Foo;
|
||||
impl Foo { fn bar(&self, _: u32) { } }
|
||||
|
||||
fn bar(_: u32) { }
|
||||
|
||||
fn main() {
|
||||
let foo = Foo;
|
||||
std::thread::spawn(move || foo.bar(<|>));
|
||||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
fn bar(&self, _: u32)
|
||||
(<_: u32>)
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn works_for_tuple_structs() {
|
||||
check(
|
||||
r#"
|
||||
/// A cool tuple struct
|
||||
struct S(u32, i32);
|
||||
fn main() {
|
||||
let s = S(0, <|>);
|
||||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
A cool tuple struct
|
||||
------
|
||||
struct S(u32, i32)
|
||||
(u32, <i32>)
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn generic_struct() {
|
||||
check(
|
||||
r#"
|
||||
struct S<T>(T);
|
||||
fn main() {
|
||||
let s = S(<|>);
|
||||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
struct S({unknown})
|
||||
(<{unknown}>)
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn works_for_enum_variants() {
|
||||
check(
|
||||
r#"
|
||||
enum E {
|
||||
/// A Variant
|
||||
A(i32),
|
||||
/// Another
|
||||
B,
|
||||
/// And C
|
||||
C { a: i32, b: i32 }
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let a = E::A(<|>);
|
||||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
A Variant
|
||||
------
|
||||
enum E::A(i32)
|
||||
(<i32>)
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cant_call_struct_record() {
|
||||
check(
|
||||
r#"
|
||||
struct S { x: u32, y: i32 }
|
||||
fn main() {
|
||||
let s = S(<|>);
|
||||
}
|
||||
"#,
|
||||
expect![[""]],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cant_call_enum_record() {
|
||||
check(
|
||||
r#"
|
||||
enum E {
|
||||
/// A Variant
|
||||
A(i32),
|
||||
/// Another
|
||||
B,
|
||||
/// And C
|
||||
C { a: i32, b: i32 }
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let a = E::C(<|>);
|
||||
}
|
||||
"#,
|
||||
expect![[""]],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fn_signature_for_call_in_macro() {
|
||||
check(
|
||||
r#"
|
||||
macro_rules! id { ($($tt:tt)*) => { $($tt)* } }
|
||||
fn foo() { }
|
||||
id! {
|
||||
fn bar() { foo(<|>); }
|
||||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
fn foo()
|
||||
()
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn call_info_for_lambdas() {
|
||||
check(
|
||||
r#"
|
||||
struct S;
|
||||
fn foo(s: S) -> i32 { 92 }
|
||||
fn main() {
|
||||
(|s| foo(s))(<|>)
|
||||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
(S) -> i32
|
||||
(<S>)
|
||||
"#]],
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn call_info_for_fn_ptr() {
|
||||
check(
|
||||
r#"
|
||||
fn main(f: fn(i32, f64) -> char) {
|
||||
f(0, <|>)
|
||||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
(i32, f64) -> char
|
||||
(i32, <f64>)
|
||||
"#]],
|
||||
)
|
||||
}
|
||||
}
|
||||
mod tests;
|
||||
|
523
crates/ide_db/src/call_info/tests.rs
Normal file
523
crates/ide_db/src/call_info/tests.rs
Normal file
@ -0,0 +1,523 @@
|
||||
use crate::RootDatabase;
|
||||
use base_db::{fixture::ChangeFixture, FilePosition};
|
||||
use expect_test::{expect, Expect};
|
||||
use test_utils::{mark, RangeOrOffset};
|
||||
|
||||
/// Creates analysis from a multi-file fixture, returns positions marked with <|>.
|
||||
pub(crate) fn position(ra_fixture: &str) -> (RootDatabase, FilePosition) {
|
||||
let change_fixture = ChangeFixture::parse(ra_fixture);
|
||||
let mut database = RootDatabase::default();
|
||||
database.apply_change(change_fixture.change);
|
||||
let (file_id, range_or_offset) = change_fixture.file_position.expect("expected a marker (<|>)");
|
||||
let offset = match range_or_offset {
|
||||
RangeOrOffset::Range(_) => panic!(),
|
||||
RangeOrOffset::Offset(it) => it,
|
||||
};
|
||||
(database, FilePosition { file_id, offset })
|
||||
}
|
||||
|
||||
fn check(ra_fixture: &str, expect: Expect) {
|
||||
let (db, position) = position(ra_fixture);
|
||||
let call_info = crate::call_info::call_info(&db, position);
|
||||
let actual = match call_info {
|
||||
Some(call_info) => {
|
||||
let docs = match &call_info.doc {
|
||||
None => "".to_string(),
|
||||
Some(docs) => format!("{}\n------\n", docs.as_str()),
|
||||
};
|
||||
let params = call_info
|
||||
.parameter_labels()
|
||||
.enumerate()
|
||||
.map(|(i, param)| {
|
||||
if Some(i) == call_info.active_parameter {
|
||||
format!("<{}>", param)
|
||||
} else {
|
||||
param.to_string()
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
.join(", ");
|
||||
format!("{}{}\n({})\n", docs, call_info.signature, params)
|
||||
}
|
||||
None => String::new(),
|
||||
};
|
||||
expect.assert_eq(&actual);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fn_signature_two_args() {
|
||||
check(
|
||||
r#"
|
||||
fn foo(x: u32, y: u32) -> u32 {x + y}
|
||||
fn bar() { foo(<|>3, ); }
|
||||
"#,
|
||||
expect![[r#"
|
||||
fn foo(x: u32, y: u32) -> u32
|
||||
(<x: u32>, y: u32)
|
||||
"#]],
|
||||
);
|
||||
check(
|
||||
r#"
|
||||
fn foo(x: u32, y: u32) -> u32 {x + y}
|
||||
fn bar() { foo(3<|>, ); }
|
||||
"#,
|
||||
expect![[r#"
|
||||
fn foo(x: u32, y: u32) -> u32
|
||||
(<x: u32>, y: u32)
|
||||
"#]],
|
||||
);
|
||||
check(
|
||||
r#"
|
||||
fn foo(x: u32, y: u32) -> u32 {x + y}
|
||||
fn bar() { foo(3,<|> ); }
|
||||
"#,
|
||||
expect![[r#"
|
||||
fn foo(x: u32, y: u32) -> u32
|
||||
(x: u32, <y: u32>)
|
||||
"#]],
|
||||
);
|
||||
check(
|
||||
r#"
|
||||
fn foo(x: u32, y: u32) -> u32 {x + y}
|
||||
fn bar() { foo(3, <|>); }
|
||||
"#,
|
||||
expect![[r#"
|
||||
fn foo(x: u32, y: u32) -> u32
|
||||
(x: u32, <y: u32>)
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fn_signature_two_args_empty() {
|
||||
check(
|
||||
r#"
|
||||
fn foo(x: u32, y: u32) -> u32 {x + y}
|
||||
fn bar() { foo(<|>); }
|
||||
"#,
|
||||
expect![[r#"
|
||||
fn foo(x: u32, y: u32) -> u32
|
||||
(<x: u32>, y: u32)
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fn_signature_two_args_first_generics() {
|
||||
check(
|
||||
r#"
|
||||
fn foo<T, U: Copy + Display>(x: T, y: U) -> u32
|
||||
where T: Copy + Display, U: Debug
|
||||
{ x + y }
|
||||
|
||||
fn bar() { foo(<|>3, ); }
|
||||
"#,
|
||||
expect![[r#"
|
||||
fn foo(x: i32, y: {unknown}) -> u32
|
||||
(<x: i32>, y: {unknown})
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fn_signature_no_params() {
|
||||
check(
|
||||
r#"
|
||||
fn foo<T>() -> T where T: Copy + Display {}
|
||||
fn bar() { foo(<|>); }
|
||||
"#,
|
||||
expect![[r#"
|
||||
fn foo() -> {unknown}
|
||||
()
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fn_signature_for_impl() {
|
||||
check(
|
||||
r#"
|
||||
struct F;
|
||||
impl F { pub fn new() { } }
|
||||
fn bar() {
|
||||
let _ : F = F::new(<|>);
|
||||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
fn new()
|
||||
()
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fn_signature_for_method_self() {
|
||||
check(
|
||||
r#"
|
||||
struct S;
|
||||
impl S { pub fn do_it(&self) {} }
|
||||
|
||||
fn bar() {
|
||||
let s: S = S;
|
||||
s.do_it(<|>);
|
||||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
fn do_it(&self)
|
||||
()
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fn_signature_for_method_with_arg() {
|
||||
check(
|
||||
r#"
|
||||
struct S;
|
||||
impl S {
|
||||
fn foo(&self, x: i32) {}
|
||||
}
|
||||
|
||||
fn main() { S.foo(<|>); }
|
||||
"#,
|
||||
expect![[r#"
|
||||
fn foo(&self, x: i32)
|
||||
(<x: i32>)
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fn_signature_for_method_with_arg_as_assoc_fn() {
|
||||
check(
|
||||
r#"
|
||||
struct S;
|
||||
impl S {
|
||||
fn foo(&self, x: i32) {}
|
||||
}
|
||||
|
||||
fn main() { S::foo(<|>); }
|
||||
"#,
|
||||
expect![[r#"
|
||||
fn foo(self: &S, x: i32)
|
||||
(<self: &S>, x: i32)
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fn_signature_with_docs_simple() {
|
||||
check(
|
||||
r#"
|
||||
/// test
|
||||
// non-doc-comment
|
||||
fn foo(j: u32) -> u32 {
|
||||
j
|
||||
}
|
||||
|
||||
fn bar() {
|
||||
let _ = foo(<|>);
|
||||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
test
|
||||
------
|
||||
fn foo(j: u32) -> u32
|
||||
(<j: u32>)
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fn_signature_with_docs() {
|
||||
check(
|
||||
r#"
|
||||
/// Adds one to the number given.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// let five = 5;
|
||||
///
|
||||
/// assert_eq!(6, my_crate::add_one(5));
|
||||
/// ```
|
||||
pub fn add_one(x: i32) -> i32 {
|
||||
x + 1
|
||||
}
|
||||
|
||||
pub fn do() {
|
||||
add_one(<|>
|
||||
}"#,
|
||||
expect![[r##"
|
||||
Adds one to the number given.
|
||||
|
||||
# Examples
|
||||
|
||||
```
|
||||
let five = 5;
|
||||
|
||||
assert_eq!(6, my_crate::add_one(5));
|
||||
```
|
||||
------
|
||||
fn add_one(x: i32) -> i32
|
||||
(<x: i32>)
|
||||
"##]],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fn_signature_with_docs_impl() {
|
||||
check(
|
||||
r#"
|
||||
struct addr;
|
||||
impl addr {
|
||||
/// Adds one to the number given.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// let five = 5;
|
||||
///
|
||||
/// assert_eq!(6, my_crate::add_one(5));
|
||||
/// ```
|
||||
pub fn add_one(x: i32) -> i32 {
|
||||
x + 1
|
||||
}
|
||||
}
|
||||
|
||||
pub fn do_it() {
|
||||
addr {};
|
||||
addr::add_one(<|>);
|
||||
}
|
||||
"#,
|
||||
expect![[r##"
|
||||
Adds one to the number given.
|
||||
|
||||
# Examples
|
||||
|
||||
```
|
||||
let five = 5;
|
||||
|
||||
assert_eq!(6, my_crate::add_one(5));
|
||||
```
|
||||
------
|
||||
fn add_one(x: i32) -> i32
|
||||
(<x: i32>)
|
||||
"##]],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fn_signature_with_docs_from_actix() {
|
||||
check(
|
||||
r#"
|
||||
struct WriteHandler<E>;
|
||||
|
||||
impl<E> WriteHandler<E> {
|
||||
/// Method is called when writer emits error.
|
||||
///
|
||||
/// If this method returns `ErrorAction::Continue` writer processing
|
||||
/// continues otherwise stream processing stops.
|
||||
fn error(&mut self, err: E, ctx: &mut Self::Context) -> Running {
|
||||
Running::Stop
|
||||
}
|
||||
|
||||
/// Method is called when writer finishes.
|
||||
///
|
||||
/// By default this method stops actor's `Context`.
|
||||
fn finished(&mut self, ctx: &mut Self::Context) {
|
||||
ctx.stop()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn foo(mut r: WriteHandler<()>) {
|
||||
r.finished(<|>);
|
||||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
Method is called when writer finishes.
|
||||
|
||||
By default this method stops actor's `Context`.
|
||||
------
|
||||
fn finished(&mut self, ctx: &mut {unknown})
|
||||
(<ctx: &mut {unknown}>)
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn call_info_bad_offset() {
|
||||
mark::check!(call_info_bad_offset);
|
||||
check(
|
||||
r#"
|
||||
fn foo(x: u32, y: u32) -> u32 {x + y}
|
||||
fn bar() { foo <|> (3, ); }
|
||||
"#,
|
||||
expect![[""]],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_nested_method_in_lambda() {
|
||||
check(
|
||||
r#"
|
||||
struct Foo;
|
||||
impl Foo { fn bar(&self, _: u32) { } }
|
||||
|
||||
fn bar(_: u32) { }
|
||||
|
||||
fn main() {
|
||||
let foo = Foo;
|
||||
std::thread::spawn(move || foo.bar(<|>));
|
||||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
fn bar(&self, _: u32)
|
||||
(<_: u32>)
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn works_for_tuple_structs() {
|
||||
check(
|
||||
r#"
|
||||
/// A cool tuple struct
|
||||
struct S(u32, i32);
|
||||
fn main() {
|
||||
let s = S(0, <|>);
|
||||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
A cool tuple struct
|
||||
------
|
||||
struct S(u32, i32)
|
||||
(u32, <i32>)
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn generic_struct() {
|
||||
check(
|
||||
r#"
|
||||
struct S<T>(T);
|
||||
fn main() {
|
||||
let s = S(<|>);
|
||||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
struct S({unknown})
|
||||
(<{unknown}>)
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn works_for_enum_variants() {
|
||||
check(
|
||||
r#"
|
||||
enum E {
|
||||
/// A Variant
|
||||
A(i32),
|
||||
/// Another
|
||||
B,
|
||||
/// And C
|
||||
C { a: i32, b: i32 }
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let a = E::A(<|>);
|
||||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
A Variant
|
||||
------
|
||||
enum E::A(i32)
|
||||
(<i32>)
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cant_call_struct_record() {
|
||||
check(
|
||||
r#"
|
||||
struct S { x: u32, y: i32 }
|
||||
fn main() {
|
||||
let s = S(<|>);
|
||||
}
|
||||
"#,
|
||||
expect![[""]],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cant_call_enum_record() {
|
||||
check(
|
||||
r#"
|
||||
enum E {
|
||||
/// A Variant
|
||||
A(i32),
|
||||
/// Another
|
||||
B,
|
||||
/// And C
|
||||
C { a: i32, b: i32 }
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let a = E::C(<|>);
|
||||
}
|
||||
"#,
|
||||
expect![[""]],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fn_signature_for_call_in_macro() {
|
||||
check(
|
||||
r#"
|
||||
macro_rules! id { ($($tt:tt)*) => { $($tt)* } }
|
||||
fn foo() { }
|
||||
id! {
|
||||
fn bar() { foo(<|>); }
|
||||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
fn foo()
|
||||
()
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn call_info_for_lambdas() {
|
||||
check(
|
||||
r#"
|
||||
struct S;
|
||||
fn foo(s: S) -> i32 { 92 }
|
||||
fn main() {
|
||||
(|s| foo(s))(<|>)
|
||||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
(S) -> i32
|
||||
(<S>)
|
||||
"#]],
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn call_info_for_fn_ptr() {
|
||||
check(
|
||||
r#"
|
||||
fn main(f: fn(i32, f64) -> char) {
|
||||
f(0, <|>)
|
||||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
(i32, f64) -> char
|
||||
(i32, <f64>)
|
||||
"#]],
|
||||
)
|
||||
}
|
@ -573,641 +573,4 @@ fn find_insert_position(
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
use test_utils::assert_eq_text;
|
||||
|
||||
#[test]
|
||||
fn insert_existing() {
|
||||
check_full("std::fs", "use std::fs;", "use std::fs;")
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn insert_start() {
|
||||
check_none(
|
||||
"std::bar::AA",
|
||||
r"
|
||||
use std::bar::B;
|
||||
use std::bar::D;
|
||||
use std::bar::F;
|
||||
use std::bar::G;",
|
||||
r"
|
||||
use std::bar::AA;
|
||||
use std::bar::B;
|
||||
use std::bar::D;
|
||||
use std::bar::F;
|
||||
use std::bar::G;",
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn insert_start_indent() {
|
||||
mark::check!(insert_use_indent_after);
|
||||
check_none(
|
||||
"std::bar::AA",
|
||||
r"
|
||||
use std::bar::B;
|
||||
use std::bar::D;",
|
||||
r"
|
||||
use std::bar::AA;
|
||||
use std::bar::B;
|
||||
use std::bar::D;",
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn insert_middle() {
|
||||
check_none(
|
||||
"std::bar::EE",
|
||||
r"
|
||||
use std::bar::A;
|
||||
use std::bar::D;
|
||||
use std::bar::F;
|
||||
use std::bar::G;",
|
||||
r"
|
||||
use std::bar::A;
|
||||
use std::bar::D;
|
||||
use std::bar::EE;
|
||||
use std::bar::F;
|
||||
use std::bar::G;",
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn insert_middle_indent() {
|
||||
check_none(
|
||||
"std::bar::EE",
|
||||
r"
|
||||
use std::bar::A;
|
||||
use std::bar::D;
|
||||
use std::bar::F;
|
||||
use std::bar::G;",
|
||||
r"
|
||||
use std::bar::A;
|
||||
use std::bar::D;
|
||||
use std::bar::EE;
|
||||
use std::bar::F;
|
||||
use std::bar::G;",
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn insert_end() {
|
||||
check_none(
|
||||
"std::bar::ZZ",
|
||||
r"
|
||||
use std::bar::A;
|
||||
use std::bar::D;
|
||||
use std::bar::F;
|
||||
use std::bar::G;",
|
||||
r"
|
||||
use std::bar::A;
|
||||
use std::bar::D;
|
||||
use std::bar::F;
|
||||
use std::bar::G;
|
||||
use std::bar::ZZ;",
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn insert_end_indent() {
|
||||
mark::check!(insert_use_indent_before);
|
||||
check_none(
|
||||
"std::bar::ZZ",
|
||||
r"
|
||||
use std::bar::A;
|
||||
use std::bar::D;
|
||||
use std::bar::F;
|
||||
use std::bar::G;",
|
||||
r"
|
||||
use std::bar::A;
|
||||
use std::bar::D;
|
||||
use std::bar::F;
|
||||
use std::bar::G;
|
||||
use std::bar::ZZ;",
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn insert_middle_nested() {
|
||||
check_none(
|
||||
"std::bar::EE",
|
||||
r"
|
||||
use std::bar::A;
|
||||
use std::bar::{D, Z}; // example of weird imports due to user
|
||||
use std::bar::F;
|
||||
use std::bar::G;",
|
||||
r"
|
||||
use std::bar::A;
|
||||
use std::bar::EE;
|
||||
use std::bar::{D, Z}; // example of weird imports due to user
|
||||
use std::bar::F;
|
||||
use std::bar::G;",
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn insert_middle_groups() {
|
||||
check_none(
|
||||
"foo::bar::GG",
|
||||
r"
|
||||
use std::bar::A;
|
||||
use std::bar::D;
|
||||
|
||||
use foo::bar::F;
|
||||
use foo::bar::H;",
|
||||
r"
|
||||
use std::bar::A;
|
||||
use std::bar::D;
|
||||
|
||||
use foo::bar::F;
|
||||
use foo::bar::GG;
|
||||
use foo::bar::H;",
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn insert_first_matching_group() {
|
||||
check_none(
|
||||
"foo::bar::GG",
|
||||
r"
|
||||
use foo::bar::A;
|
||||
use foo::bar::D;
|
||||
|
||||
use std;
|
||||
|
||||
use foo::bar::F;
|
||||
use foo::bar::H;",
|
||||
r"
|
||||
use foo::bar::A;
|
||||
use foo::bar::D;
|
||||
use foo::bar::GG;
|
||||
|
||||
use std;
|
||||
|
||||
use foo::bar::F;
|
||||
use foo::bar::H;",
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn insert_missing_group_std() {
|
||||
check_none(
|
||||
"std::fmt",
|
||||
r"
|
||||
use foo::bar::A;
|
||||
use foo::bar::D;",
|
||||
r"
|
||||
use std::fmt;
|
||||
|
||||
use foo::bar::A;
|
||||
use foo::bar::D;",
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn insert_missing_group_self() {
|
||||
check_none(
|
||||
"self::fmt",
|
||||
r"
|
||||
use foo::bar::A;
|
||||
use foo::bar::D;",
|
||||
r"
|
||||
use foo::bar::A;
|
||||
use foo::bar::D;
|
||||
|
||||
use self::fmt;",
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn insert_no_imports() {
|
||||
check_full(
|
||||
"foo::bar",
|
||||
"fn main() {}",
|
||||
r"use foo::bar;
|
||||
|
||||
fn main() {}",
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn insert_empty_file() {
|
||||
// empty files will get two trailing newlines
|
||||
// this is due to the test case insert_no_imports above
|
||||
check_full(
|
||||
"foo::bar",
|
||||
"",
|
||||
r"use foo::bar;
|
||||
|
||||
",
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn insert_empty_module() {
|
||||
mark::check!(insert_use_no_indent_after);
|
||||
check(
|
||||
"foo::bar",
|
||||
"mod x {}",
|
||||
r"{
|
||||
use foo::bar;
|
||||
}",
|
||||
None,
|
||||
true,
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn insert_after_inner_attr() {
|
||||
check_full(
|
||||
"foo::bar",
|
||||
r"#![allow(unused_imports)]",
|
||||
r"#![allow(unused_imports)]
|
||||
|
||||
use foo::bar;",
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn insert_after_inner_attr2() {
|
||||
check_full(
|
||||
"foo::bar",
|
||||
r"#![allow(unused_imports)]
|
||||
|
||||
#![no_std]
|
||||
fn main() {}",
|
||||
r"#![allow(unused_imports)]
|
||||
|
||||
#![no_std]
|
||||
|
||||
use foo::bar;
|
||||
fn main() {}",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn inserts_after_single_line_inner_comments() {
|
||||
check_none(
|
||||
"foo::bar::Baz",
|
||||
"//! Single line inner comments do not allow any code before them.",
|
||||
r#"//! Single line inner comments do not allow any code before them.
|
||||
|
||||
use foo::bar::Baz;"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn inserts_after_multiline_inner_comments() {
|
||||
check_none(
|
||||
"foo::bar::Baz",
|
||||
r#"/*! Multiline inner comments do not allow any code before them. */
|
||||
|
||||
/*! Still an inner comment, cannot place any code before. */
|
||||
fn main() {}"#,
|
||||
r#"/*! Multiline inner comments do not allow any code before them. */
|
||||
|
||||
/*! Still an inner comment, cannot place any code before. */
|
||||
|
||||
use foo::bar::Baz;
|
||||
fn main() {}"#,
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn inserts_after_all_inner_items() {
|
||||
check_none(
|
||||
"foo::bar::Baz",
|
||||
r#"#![allow(unused_imports)]
|
||||
/*! Multiline line comment 2 */
|
||||
|
||||
|
||||
//! Single line comment 1
|
||||
#![no_std]
|
||||
//! Single line comment 2
|
||||
fn main() {}"#,
|
||||
r#"#![allow(unused_imports)]
|
||||
/*! Multiline line comment 2 */
|
||||
|
||||
|
||||
//! Single line comment 1
|
||||
#![no_std]
|
||||
//! Single line comment 2
|
||||
|
||||
use foo::bar::Baz;
|
||||
fn main() {}"#,
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn merge_groups() {
|
||||
check_last("std::io", r"use std::fmt;", r"use std::{fmt, io};")
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn merge_groups_last() {
|
||||
check_last(
|
||||
"std::io",
|
||||
r"use std::fmt::{Result, Display};",
|
||||
r"use std::fmt::{Result, Display};
|
||||
use std::io;",
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn merge_last_into_self() {
|
||||
check_last("foo::bar::baz", r"use foo::bar;", r"use foo::bar::{self, baz};");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn merge_groups_full() {
|
||||
check_full(
|
||||
"std::io",
|
||||
r"use std::fmt::{Result, Display};",
|
||||
r"use std::{fmt::{Result, Display}, io};",
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn merge_groups_long_full() {
|
||||
check_full(
|
||||
"std::foo::bar::Baz",
|
||||
r"use std::foo::bar::Qux;",
|
||||
r"use std::foo::bar::{Baz, Qux};",
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn merge_groups_long_last() {
|
||||
check_last(
|
||||
"std::foo::bar::Baz",
|
||||
r"use std::foo::bar::Qux;",
|
||||
r"use std::foo::bar::{Baz, Qux};",
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn merge_groups_long_full_list() {
|
||||
check_full(
|
||||
"std::foo::bar::Baz",
|
||||
r"use std::foo::bar::{Qux, Quux};",
|
||||
r"use std::foo::bar::{Baz, Quux, Qux};",
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn merge_groups_long_last_list() {
|
||||
check_last(
|
||||
"std::foo::bar::Baz",
|
||||
r"use std::foo::bar::{Qux, Quux};",
|
||||
r"use std::foo::bar::{Baz, Quux, Qux};",
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn merge_groups_long_full_nested() {
|
||||
check_full(
|
||||
"std::foo::bar::Baz",
|
||||
r"use std::foo::bar::{Qux, quux::{Fez, Fizz}};",
|
||||
r"use std::foo::bar::{Baz, Qux, quux::{Fez, Fizz}};",
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn merge_groups_long_last_nested() {
|
||||
check_last(
|
||||
"std::foo::bar::Baz",
|
||||
r"use std::foo::bar::{Qux, quux::{Fez, Fizz}};",
|
||||
r"use std::foo::bar::Baz;
|
||||
use std::foo::bar::{Qux, quux::{Fez, Fizz}};",
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn merge_groups_full_nested_deep() {
|
||||
check_full(
|
||||
"std::foo::bar::quux::Baz",
|
||||
r"use std::foo::bar::{Qux, quux::{Fez, Fizz}};",
|
||||
r"use std::foo::bar::{Qux, quux::{Baz, Fez, Fizz}};",
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn merge_groups_full_nested_long() {
|
||||
check_full(
|
||||
"std::foo::bar::Baz",
|
||||
r"use std::{foo::bar::Qux};",
|
||||
r"use std::{foo::bar::{Baz, Qux}};",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn merge_groups_last_nested_long() {
|
||||
check_full(
|
||||
"std::foo::bar::Baz",
|
||||
r"use std::{foo::bar::Qux};",
|
||||
r"use std::{foo::bar::{Baz, Qux}};",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn merge_groups_skip_pub() {
|
||||
check_full(
|
||||
"std::io",
|
||||
r"pub use std::fmt::{Result, Display};",
|
||||
r"pub use std::fmt::{Result, Display};
|
||||
use std::io;",
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn merge_groups_skip_pub_crate() {
|
||||
check_full(
|
||||
"std::io",
|
||||
r"pub(crate) use std::fmt::{Result, Display};",
|
||||
r"pub(crate) use std::fmt::{Result, Display};
|
||||
use std::io;",
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore] // FIXME: Support this
|
||||
fn split_out_merge() {
|
||||
check_last(
|
||||
"std::fmt::Result",
|
||||
r"use std::{fmt, io};",
|
||||
r"use std::fmt::{self, Result};
|
||||
use std::io;",
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn merge_into_module_import() {
|
||||
check_full(
|
||||
"std::fmt::Result",
|
||||
r"use std::{fmt, io};",
|
||||
r"use std::{fmt::{self, Result}, io};",
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn merge_groups_self() {
|
||||
check_full("std::fmt::Debug", r"use std::fmt;", r"use std::fmt::{self, Debug};")
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn merge_mod_into_glob() {
|
||||
check_full(
|
||||
"token::TokenKind",
|
||||
r"use token::TokenKind::*;",
|
||||
r"use token::TokenKind::{*, self};",
|
||||
)
|
||||
// FIXME: have it emit `use token::TokenKind::{self, *}`?
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn merge_self_glob() {
|
||||
check_full("self", r"use self::*;", r"use self::{*, self};")
|
||||
// FIXME: have it emit `use {self, *}`?
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn merge_glob_nested() {
|
||||
check_full(
|
||||
"foo::bar::quux::Fez",
|
||||
r"use foo::bar::{Baz, quux::*};",
|
||||
r"use foo::bar::{Baz, quux::{self::*, Fez}};",
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn merge_nested_considers_first_segments() {
|
||||
check_full(
|
||||
"hir_ty::display::write_bounds_like_dyn_trait",
|
||||
r"use hir_ty::{autoderef, display::{HirDisplayError, HirFormatter}, method_resolution};",
|
||||
r"use hir_ty::{autoderef, display::{HirDisplayError, HirFormatter, write_bounds_like_dyn_trait}, method_resolution};",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn skip_merge_last_too_long() {
|
||||
check_last(
|
||||
"foo::bar",
|
||||
r"use foo::bar::baz::Qux;",
|
||||
r"use foo::bar;
|
||||
use foo::bar::baz::Qux;",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn skip_merge_last_too_long2() {
|
||||
check_last(
|
||||
"foo::bar::baz::Qux",
|
||||
r"use foo::bar;",
|
||||
r"use foo::bar;
|
||||
use foo::bar::baz::Qux;",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn insert_short_before_long() {
|
||||
check_none(
|
||||
"foo::bar",
|
||||
r"use foo::bar::baz::Qux;",
|
||||
r"use foo::bar;
|
||||
use foo::bar::baz::Qux;",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn merge_last_fail() {
|
||||
check_merge_only_fail(
|
||||
r"use foo::bar::{baz::{Qux, Fez}};",
|
||||
r"use foo::bar::{baaz::{Quux, Feez}};",
|
||||
MergeBehaviour::Last,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn merge_last_fail1() {
|
||||
check_merge_only_fail(
|
||||
r"use foo::bar::{baz::{Qux, Fez}};",
|
||||
r"use foo::bar::baaz::{Quux, Feez};",
|
||||
MergeBehaviour::Last,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn merge_last_fail2() {
|
||||
check_merge_only_fail(
|
||||
r"use foo::bar::baz::{Qux, Fez};",
|
||||
r"use foo::bar::{baaz::{Quux, Feez}};",
|
||||
MergeBehaviour::Last,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn merge_last_fail3() {
|
||||
check_merge_only_fail(
|
||||
r"use foo::bar::baz::{Qux, Fez};",
|
||||
r"use foo::bar::baaz::{Quux, Feez};",
|
||||
MergeBehaviour::Last,
|
||||
);
|
||||
}
|
||||
|
||||
fn check(
|
||||
path: &str,
|
||||
ra_fixture_before: &str,
|
||||
ra_fixture_after: &str,
|
||||
mb: Option<MergeBehaviour>,
|
||||
module: bool,
|
||||
) {
|
||||
let mut syntax = ast::SourceFile::parse(ra_fixture_before).tree().syntax().clone();
|
||||
if module {
|
||||
syntax = syntax.descendants().find_map(ast::Module::cast).unwrap().syntax().clone();
|
||||
}
|
||||
let file = super::ImportScope::from(syntax).unwrap();
|
||||
let path = ast::SourceFile::parse(&format!("use {};", path))
|
||||
.tree()
|
||||
.syntax()
|
||||
.descendants()
|
||||
.find_map(ast::Path::cast)
|
||||
.unwrap();
|
||||
|
||||
let rewriter = insert_use(&file, path, mb);
|
||||
let result = rewriter.rewrite(file.as_syntax_node()).to_string();
|
||||
assert_eq_text!(&result, ra_fixture_after);
|
||||
}
|
||||
|
||||
fn check_full(path: &str, ra_fixture_before: &str, ra_fixture_after: &str) {
|
||||
check(path, ra_fixture_before, ra_fixture_after, Some(MergeBehaviour::Full), false)
|
||||
}
|
||||
|
||||
fn check_last(path: &str, ra_fixture_before: &str, ra_fixture_after: &str) {
|
||||
check(path, ra_fixture_before, ra_fixture_after, Some(MergeBehaviour::Last), false)
|
||||
}
|
||||
|
||||
fn check_none(path: &str, ra_fixture_before: &str, ra_fixture_after: &str) {
|
||||
check(path, ra_fixture_before, ra_fixture_after, None, false)
|
||||
}
|
||||
|
||||
fn check_merge_only_fail(ra_fixture0: &str, ra_fixture1: &str, mb: MergeBehaviour) {
|
||||
let use0 = ast::SourceFile::parse(ra_fixture0)
|
||||
.tree()
|
||||
.syntax()
|
||||
.descendants()
|
||||
.find_map(ast::Use::cast)
|
||||
.unwrap();
|
||||
|
||||
let use1 = ast::SourceFile::parse(ra_fixture1)
|
||||
.tree()
|
||||
.syntax()
|
||||
.descendants()
|
||||
.find_map(ast::Use::cast)
|
||||
.unwrap();
|
||||
|
||||
let result = try_merge_imports(&use0, &use1, mb);
|
||||
assert_eq!(result.map(|u| u.to_string()), None);
|
||||
}
|
||||
}
|
||||
mod tests;
|
||||
|
620
crates/ide_db/src/helpers/insert_use/tests.rs
Normal file
620
crates/ide_db/src/helpers/insert_use/tests.rs
Normal file
@ -0,0 +1,620 @@
|
||||
use super::*;
|
||||
|
||||
use test_utils::assert_eq_text;
|
||||
|
||||
#[test]
|
||||
fn insert_existing() {
|
||||
check_full("std::fs", "use std::fs;", "use std::fs;")
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn insert_start() {
|
||||
check_none(
|
||||
"std::bar::AA",
|
||||
r"
|
||||
use std::bar::B;
|
||||
use std::bar::D;
|
||||
use std::bar::F;
|
||||
use std::bar::G;",
|
||||
r"
|
||||
use std::bar::AA;
|
||||
use std::bar::B;
|
||||
use std::bar::D;
|
||||
use std::bar::F;
|
||||
use std::bar::G;",
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn insert_start_indent() {
|
||||
mark::check!(insert_use_indent_after);
|
||||
check_none(
|
||||
"std::bar::AA",
|
||||
r"
|
||||
use std::bar::B;
|
||||
use std::bar::D;",
|
||||
r"
|
||||
use std::bar::AA;
|
||||
use std::bar::B;
|
||||
use std::bar::D;",
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn insert_middle() {
|
||||
check_none(
|
||||
"std::bar::EE",
|
||||
r"
|
||||
use std::bar::A;
|
||||
use std::bar::D;
|
||||
use std::bar::F;
|
||||
use std::bar::G;",
|
||||
r"
|
||||
use std::bar::A;
|
||||
use std::bar::D;
|
||||
use std::bar::EE;
|
||||
use std::bar::F;
|
||||
use std::bar::G;",
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn insert_middle_indent() {
|
||||
check_none(
|
||||
"std::bar::EE",
|
||||
r"
|
||||
use std::bar::A;
|
||||
use std::bar::D;
|
||||
use std::bar::F;
|
||||
use std::bar::G;",
|
||||
r"
|
||||
use std::bar::A;
|
||||
use std::bar::D;
|
||||
use std::bar::EE;
|
||||
use std::bar::F;
|
||||
use std::bar::G;",
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn insert_end() {
|
||||
check_none(
|
||||
"std::bar::ZZ",
|
||||
r"
|
||||
use std::bar::A;
|
||||
use std::bar::D;
|
||||
use std::bar::F;
|
||||
use std::bar::G;",
|
||||
r"
|
||||
use std::bar::A;
|
||||
use std::bar::D;
|
||||
use std::bar::F;
|
||||
use std::bar::G;
|
||||
use std::bar::ZZ;",
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn insert_end_indent() {
|
||||
mark::check!(insert_use_indent_before);
|
||||
check_none(
|
||||
"std::bar::ZZ",
|
||||
r"
|
||||
use std::bar::A;
|
||||
use std::bar::D;
|
||||
use std::bar::F;
|
||||
use std::bar::G;",
|
||||
r"
|
||||
use std::bar::A;
|
||||
use std::bar::D;
|
||||
use std::bar::F;
|
||||
use std::bar::G;
|
||||
use std::bar::ZZ;",
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn insert_middle_nested() {
|
||||
check_none(
|
||||
"std::bar::EE",
|
||||
r"
|
||||
use std::bar::A;
|
||||
use std::bar::{D, Z}; // example of weird imports due to user
|
||||
use std::bar::F;
|
||||
use std::bar::G;",
|
||||
r"
|
||||
use std::bar::A;
|
||||
use std::bar::EE;
|
||||
use std::bar::{D, Z}; // example of weird imports due to user
|
||||
use std::bar::F;
|
||||
use std::bar::G;",
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn insert_middle_groups() {
|
||||
check_none(
|
||||
"foo::bar::GG",
|
||||
r"
|
||||
use std::bar::A;
|
||||
use std::bar::D;
|
||||
|
||||
use foo::bar::F;
|
||||
use foo::bar::H;",
|
||||
r"
|
||||
use std::bar::A;
|
||||
use std::bar::D;
|
||||
|
||||
use foo::bar::F;
|
||||
use foo::bar::GG;
|
||||
use foo::bar::H;",
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn insert_first_matching_group() {
|
||||
check_none(
|
||||
"foo::bar::GG",
|
||||
r"
|
||||
use foo::bar::A;
|
||||
use foo::bar::D;
|
||||
|
||||
use std;
|
||||
|
||||
use foo::bar::F;
|
||||
use foo::bar::H;",
|
||||
r"
|
||||
use foo::bar::A;
|
||||
use foo::bar::D;
|
||||
use foo::bar::GG;
|
||||
|
||||
use std;
|
||||
|
||||
use foo::bar::F;
|
||||
use foo::bar::H;",
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn insert_missing_group_std() {
|
||||
check_none(
|
||||
"std::fmt",
|
||||
r"
|
||||
use foo::bar::A;
|
||||
use foo::bar::D;",
|
||||
r"
|
||||
use std::fmt;
|
||||
|
||||
use foo::bar::A;
|
||||
use foo::bar::D;",
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn insert_missing_group_self() {
|
||||
check_none(
|
||||
"self::fmt",
|
||||
r"
|
||||
use foo::bar::A;
|
||||
use foo::bar::D;",
|
||||
r"
|
||||
use foo::bar::A;
|
||||
use foo::bar::D;
|
||||
|
||||
use self::fmt;",
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn insert_no_imports() {
|
||||
check_full(
|
||||
"foo::bar",
|
||||
"fn main() {}",
|
||||
r"use foo::bar;
|
||||
|
||||
fn main() {}",
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn insert_empty_file() {
|
||||
// empty files will get two trailing newlines
|
||||
// this is due to the test case insert_no_imports above
|
||||
check_full(
|
||||
"foo::bar",
|
||||
"",
|
||||
r"use foo::bar;
|
||||
|
||||
",
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn insert_empty_module() {
|
||||
mark::check!(insert_use_no_indent_after);
|
||||
check(
|
||||
"foo::bar",
|
||||
"mod x {}",
|
||||
r"{
|
||||
use foo::bar;
|
||||
}",
|
||||
None,
|
||||
true,
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn insert_after_inner_attr() {
|
||||
check_full(
|
||||
"foo::bar",
|
||||
r"#![allow(unused_imports)]",
|
||||
r"#![allow(unused_imports)]
|
||||
|
||||
use foo::bar;",
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn insert_after_inner_attr2() {
|
||||
check_full(
|
||||
"foo::bar",
|
||||
r"#![allow(unused_imports)]
|
||||
|
||||
#![no_std]
|
||||
fn main() {}",
|
||||
r"#![allow(unused_imports)]
|
||||
|
||||
#![no_std]
|
||||
|
||||
use foo::bar;
|
||||
fn main() {}",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn inserts_after_single_line_inner_comments() {
|
||||
check_none(
|
||||
"foo::bar::Baz",
|
||||
"//! Single line inner comments do not allow any code before them.",
|
||||
r#"//! Single line inner comments do not allow any code before them.
|
||||
|
||||
use foo::bar::Baz;"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn inserts_after_multiline_inner_comments() {
|
||||
check_none(
|
||||
"foo::bar::Baz",
|
||||
r#"/*! Multiline inner comments do not allow any code before them. */
|
||||
|
||||
/*! Still an inner comment, cannot place any code before. */
|
||||
fn main() {}"#,
|
||||
r#"/*! Multiline inner comments do not allow any code before them. */
|
||||
|
||||
/*! Still an inner comment, cannot place any code before. */
|
||||
|
||||
use foo::bar::Baz;
|
||||
fn main() {}"#,
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn inserts_after_all_inner_items() {
|
||||
check_none(
|
||||
"foo::bar::Baz",
|
||||
r#"#![allow(unused_imports)]
|
||||
/*! Multiline line comment 2 */
|
||||
|
||||
|
||||
//! Single line comment 1
|
||||
#![no_std]
|
||||
//! Single line comment 2
|
||||
fn main() {}"#,
|
||||
r#"#![allow(unused_imports)]
|
||||
/*! Multiline line comment 2 */
|
||||
|
||||
|
||||
//! Single line comment 1
|
||||
#![no_std]
|
||||
//! Single line comment 2
|
||||
|
||||
use foo::bar::Baz;
|
||||
fn main() {}"#,
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn merge_groups() {
|
||||
check_last("std::io", r"use std::fmt;", r"use std::{fmt, io};")
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn merge_groups_last() {
|
||||
check_last(
|
||||
"std::io",
|
||||
r"use std::fmt::{Result, Display};",
|
||||
r"use std::fmt::{Result, Display};
|
||||
use std::io;",
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn merge_last_into_self() {
|
||||
check_last("foo::bar::baz", r"use foo::bar;", r"use foo::bar::{self, baz};");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn merge_groups_full() {
|
||||
check_full(
|
||||
"std::io",
|
||||
r"use std::fmt::{Result, Display};",
|
||||
r"use std::{fmt::{Result, Display}, io};",
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn merge_groups_long_full() {
|
||||
check_full("std::foo::bar::Baz", r"use std::foo::bar::Qux;", r"use std::foo::bar::{Baz, Qux};")
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn merge_groups_long_last() {
|
||||
check_last("std::foo::bar::Baz", r"use std::foo::bar::Qux;", r"use std::foo::bar::{Baz, Qux};")
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn merge_groups_long_full_list() {
|
||||
check_full(
|
||||
"std::foo::bar::Baz",
|
||||
r"use std::foo::bar::{Qux, Quux};",
|
||||
r"use std::foo::bar::{Baz, Quux, Qux};",
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn merge_groups_long_last_list() {
|
||||
check_last(
|
||||
"std::foo::bar::Baz",
|
||||
r"use std::foo::bar::{Qux, Quux};",
|
||||
r"use std::foo::bar::{Baz, Quux, Qux};",
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn merge_groups_long_full_nested() {
|
||||
check_full(
|
||||
"std::foo::bar::Baz",
|
||||
r"use std::foo::bar::{Qux, quux::{Fez, Fizz}};",
|
||||
r"use std::foo::bar::{Baz, Qux, quux::{Fez, Fizz}};",
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn merge_groups_long_last_nested() {
|
||||
check_last(
|
||||
"std::foo::bar::Baz",
|
||||
r"use std::foo::bar::{Qux, quux::{Fez, Fizz}};",
|
||||
r"use std::foo::bar::Baz;
|
||||
use std::foo::bar::{Qux, quux::{Fez, Fizz}};",
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn merge_groups_full_nested_deep() {
|
||||
check_full(
|
||||
"std::foo::bar::quux::Baz",
|
||||
r"use std::foo::bar::{Qux, quux::{Fez, Fizz}};",
|
||||
r"use std::foo::bar::{Qux, quux::{Baz, Fez, Fizz}};",
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn merge_groups_full_nested_long() {
|
||||
check_full(
|
||||
"std::foo::bar::Baz",
|
||||
r"use std::{foo::bar::Qux};",
|
||||
r"use std::{foo::bar::{Baz, Qux}};",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn merge_groups_last_nested_long() {
|
||||
check_full(
|
||||
"std::foo::bar::Baz",
|
||||
r"use std::{foo::bar::Qux};",
|
||||
r"use std::{foo::bar::{Baz, Qux}};",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn merge_groups_skip_pub() {
|
||||
check_full(
|
||||
"std::io",
|
||||
r"pub use std::fmt::{Result, Display};",
|
||||
r"pub use std::fmt::{Result, Display};
|
||||
use std::io;",
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn merge_groups_skip_pub_crate() {
|
||||
check_full(
|
||||
"std::io",
|
||||
r"pub(crate) use std::fmt::{Result, Display};",
|
||||
r"pub(crate) use std::fmt::{Result, Display};
|
||||
use std::io;",
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore] // FIXME: Support this
|
||||
fn split_out_merge() {
|
||||
check_last(
|
||||
"std::fmt::Result",
|
||||
r"use std::{fmt, io};",
|
||||
r"use std::fmt::{self, Result};
|
||||
use std::io;",
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn merge_into_module_import() {
|
||||
check_full("std::fmt::Result", r"use std::{fmt, io};", r"use std::{fmt::{self, Result}, io};")
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn merge_groups_self() {
|
||||
check_full("std::fmt::Debug", r"use std::fmt;", r"use std::fmt::{self, Debug};")
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn merge_mod_into_glob() {
|
||||
check_full("token::TokenKind", r"use token::TokenKind::*;", r"use token::TokenKind::{*, self};")
|
||||
// FIXME: have it emit `use token::TokenKind::{self, *}`?
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn merge_self_glob() {
|
||||
check_full("self", r"use self::*;", r"use self::{*, self};")
|
||||
// FIXME: have it emit `use {self, *}`?
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn merge_glob_nested() {
|
||||
check_full(
|
||||
"foo::bar::quux::Fez",
|
||||
r"use foo::bar::{Baz, quux::*};",
|
||||
r"use foo::bar::{Baz, quux::{self::*, Fez}};",
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn merge_nested_considers_first_segments() {
|
||||
check_full(
|
||||
"hir_ty::display::write_bounds_like_dyn_trait",
|
||||
r"use hir_ty::{autoderef, display::{HirDisplayError, HirFormatter}, method_resolution};",
|
||||
r"use hir_ty::{autoderef, display::{HirDisplayError, HirFormatter, write_bounds_like_dyn_trait}, method_resolution};",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn skip_merge_last_too_long() {
|
||||
check_last(
|
||||
"foo::bar",
|
||||
r"use foo::bar::baz::Qux;",
|
||||
r"use foo::bar;
|
||||
use foo::bar::baz::Qux;",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn skip_merge_last_too_long2() {
|
||||
check_last(
|
||||
"foo::bar::baz::Qux",
|
||||
r"use foo::bar;",
|
||||
r"use foo::bar;
|
||||
use foo::bar::baz::Qux;",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn insert_short_before_long() {
|
||||
check_none(
|
||||
"foo::bar",
|
||||
r"use foo::bar::baz::Qux;",
|
||||
r"use foo::bar;
|
||||
use foo::bar::baz::Qux;",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn merge_last_fail() {
|
||||
check_merge_only_fail(
|
||||
r"use foo::bar::{baz::{Qux, Fez}};",
|
||||
r"use foo::bar::{baaz::{Quux, Feez}};",
|
||||
MergeBehaviour::Last,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn merge_last_fail1() {
|
||||
check_merge_only_fail(
|
||||
r"use foo::bar::{baz::{Qux, Fez}};",
|
||||
r"use foo::bar::baaz::{Quux, Feez};",
|
||||
MergeBehaviour::Last,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn merge_last_fail2() {
|
||||
check_merge_only_fail(
|
||||
r"use foo::bar::baz::{Qux, Fez};",
|
||||
r"use foo::bar::{baaz::{Quux, Feez}};",
|
||||
MergeBehaviour::Last,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn merge_last_fail3() {
|
||||
check_merge_only_fail(
|
||||
r"use foo::bar::baz::{Qux, Fez};",
|
||||
r"use foo::bar::baaz::{Quux, Feez};",
|
||||
MergeBehaviour::Last,
|
||||
);
|
||||
}
|
||||
|
||||
fn check(
|
||||
path: &str,
|
||||
ra_fixture_before: &str,
|
||||
ra_fixture_after: &str,
|
||||
mb: Option<MergeBehaviour>,
|
||||
module: bool,
|
||||
) {
|
||||
let mut syntax = ast::SourceFile::parse(ra_fixture_before).tree().syntax().clone();
|
||||
if module {
|
||||
syntax = syntax.descendants().find_map(ast::Module::cast).unwrap().syntax().clone();
|
||||
}
|
||||
let file = super::ImportScope::from(syntax).unwrap();
|
||||
let path = ast::SourceFile::parse(&format!("use {};", path))
|
||||
.tree()
|
||||
.syntax()
|
||||
.descendants()
|
||||
.find_map(ast::Path::cast)
|
||||
.unwrap();
|
||||
|
||||
let rewriter = insert_use(&file, path, mb);
|
||||
let result = rewriter.rewrite(file.as_syntax_node()).to_string();
|
||||
assert_eq_text!(&result, ra_fixture_after);
|
||||
}
|
||||
|
||||
fn check_full(path: &str, ra_fixture_before: &str, ra_fixture_after: &str) {
|
||||
check(path, ra_fixture_before, ra_fixture_after, Some(MergeBehaviour::Full), false)
|
||||
}
|
||||
|
||||
fn check_last(path: &str, ra_fixture_before: &str, ra_fixture_after: &str) {
|
||||
check(path, ra_fixture_before, ra_fixture_after, Some(MergeBehaviour::Last), false)
|
||||
}
|
||||
|
||||
fn check_none(path: &str, ra_fixture_before: &str, ra_fixture_after: &str) {
|
||||
check(path, ra_fixture_before, ra_fixture_after, None, false)
|
||||
}
|
||||
|
||||
fn check_merge_only_fail(ra_fixture0: &str, ra_fixture1: &str, mb: MergeBehaviour) {
|
||||
let use0 = ast::SourceFile::parse(ra_fixture0)
|
||||
.tree()
|
||||
.syntax()
|
||||
.descendants()
|
||||
.find_map(ast::Use::cast)
|
||||
.unwrap();
|
||||
|
||||
let use1 = ast::SourceFile::parse(ra_fixture1)
|
||||
.tree()
|
||||
.syntax()
|
||||
.descendants()
|
||||
.find_map(ast::Use::cast)
|
||||
.unwrap();
|
||||
|
||||
let result = try_merge_imports(&use0, &use1, mb);
|
||||
assert_eq!(result.map(|u| u.to_string()), None);
|
||||
}
|
@ -149,133 +149,4 @@ fn utf16_to_utf8_col(&self, line: u32, mut col: u32) -> TextSize {
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_line_index() {
|
||||
let text = "hello\nworld";
|
||||
let index = LineIndex::new(text);
|
||||
assert_eq!(index.line_col(0.into()), LineCol { line: 0, col_utf16: 0 });
|
||||
assert_eq!(index.line_col(1.into()), LineCol { line: 0, col_utf16: 1 });
|
||||
assert_eq!(index.line_col(5.into()), LineCol { line: 0, col_utf16: 5 });
|
||||
assert_eq!(index.line_col(6.into()), LineCol { line: 1, col_utf16: 0 });
|
||||
assert_eq!(index.line_col(7.into()), LineCol { line: 1, col_utf16: 1 });
|
||||
assert_eq!(index.line_col(8.into()), LineCol { line: 1, col_utf16: 2 });
|
||||
assert_eq!(index.line_col(10.into()), LineCol { line: 1, col_utf16: 4 });
|
||||
assert_eq!(index.line_col(11.into()), LineCol { line: 1, col_utf16: 5 });
|
||||
assert_eq!(index.line_col(12.into()), LineCol { line: 1, col_utf16: 6 });
|
||||
|
||||
let text = "\nhello\nworld";
|
||||
let index = LineIndex::new(text);
|
||||
assert_eq!(index.line_col(0.into()), LineCol { line: 0, col_utf16: 0 });
|
||||
assert_eq!(index.line_col(1.into()), LineCol { line: 1, col_utf16: 0 });
|
||||
assert_eq!(index.line_col(2.into()), LineCol { line: 1, col_utf16: 1 });
|
||||
assert_eq!(index.line_col(6.into()), LineCol { line: 1, col_utf16: 5 });
|
||||
assert_eq!(index.line_col(7.into()), LineCol { line: 2, col_utf16: 0 });
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_char_len() {
|
||||
assert_eq!('メ'.len_utf8(), 3);
|
||||
assert_eq!('メ'.len_utf16(), 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_empty_index() {
|
||||
let col_index = LineIndex::new(
|
||||
"
|
||||
const C: char = 'x';
|
||||
",
|
||||
);
|
||||
assert_eq!(col_index.utf16_lines.len(), 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_single_char() {
|
||||
let col_index = LineIndex::new(
|
||||
"
|
||||
const C: char = 'メ';
|
||||
",
|
||||
);
|
||||
|
||||
assert_eq!(col_index.utf16_lines.len(), 1);
|
||||
assert_eq!(col_index.utf16_lines[&1].len(), 1);
|
||||
assert_eq!(col_index.utf16_lines[&1][0], Utf16Char { start: 17.into(), end: 20.into() });
|
||||
|
||||
// UTF-8 to UTF-16, no changes
|
||||
assert_eq!(col_index.utf8_to_utf16_col(1, 15.into()), 15);
|
||||
|
||||
// UTF-8 to UTF-16
|
||||
assert_eq!(col_index.utf8_to_utf16_col(1, 22.into()), 20);
|
||||
|
||||
// UTF-16 to UTF-8, no changes
|
||||
assert_eq!(col_index.utf16_to_utf8_col(1, 15), TextSize::from(15));
|
||||
|
||||
// UTF-16 to UTF-8
|
||||
assert_eq!(col_index.utf16_to_utf8_col(1, 19), TextSize::from(21));
|
||||
|
||||
let col_index = LineIndex::new("a𐐏b");
|
||||
assert_eq!(col_index.utf16_to_utf8_col(0, 3), TextSize::from(5));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_string() {
|
||||
let col_index = LineIndex::new(
|
||||
"
|
||||
const C: char = \"メ メ\";
|
||||
",
|
||||
);
|
||||
|
||||
assert_eq!(col_index.utf16_lines.len(), 1);
|
||||
assert_eq!(col_index.utf16_lines[&1].len(), 2);
|
||||
assert_eq!(col_index.utf16_lines[&1][0], Utf16Char { start: 17.into(), end: 20.into() });
|
||||
assert_eq!(col_index.utf16_lines[&1][1], Utf16Char { start: 21.into(), end: 24.into() });
|
||||
|
||||
// UTF-8 to UTF-16
|
||||
assert_eq!(col_index.utf8_to_utf16_col(1, 15.into()), 15);
|
||||
|
||||
assert_eq!(col_index.utf8_to_utf16_col(1, 21.into()), 19);
|
||||
assert_eq!(col_index.utf8_to_utf16_col(1, 25.into()), 21);
|
||||
|
||||
assert!(col_index.utf8_to_utf16_col(2, 15.into()) == 15);
|
||||
|
||||
// UTF-16 to UTF-8
|
||||
assert_eq!(col_index.utf16_to_utf8_col(1, 15), TextSize::from(15));
|
||||
|
||||
// メ UTF-8: 0xE3 0x83 0xA1, UTF-16: 0x30E1
|
||||
assert_eq!(col_index.utf16_to_utf8_col(1, 17), TextSize::from(17)); // first メ at 17..20
|
||||
assert_eq!(col_index.utf16_to_utf8_col(1, 18), TextSize::from(20)); // space
|
||||
assert_eq!(col_index.utf16_to_utf8_col(1, 19), TextSize::from(21)); // second メ at 21..24
|
||||
|
||||
assert_eq!(col_index.utf16_to_utf8_col(2, 15), TextSize::from(15));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_splitlines() {
|
||||
fn r(lo: u32, hi: u32) -> TextRange {
|
||||
TextRange::new(lo.into(), hi.into())
|
||||
}
|
||||
|
||||
let text = "a\nbb\nccc\n";
|
||||
let line_index = LineIndex::new(text);
|
||||
|
||||
let actual = line_index.lines(r(0, 9)).collect::<Vec<_>>();
|
||||
let expected = vec![r(0, 2), r(2, 5), r(5, 9)];
|
||||
assert_eq!(actual, expected);
|
||||
|
||||
let text = "";
|
||||
let line_index = LineIndex::new(text);
|
||||
|
||||
let actual = line_index.lines(r(0, 0)).collect::<Vec<_>>();
|
||||
let expected = vec![];
|
||||
assert_eq!(actual, expected);
|
||||
|
||||
let text = "\n";
|
||||
let line_index = LineIndex::new(text);
|
||||
|
||||
let actual = line_index.lines(r(0, 1)).collect::<Vec<_>>();
|
||||
let expected = vec![r(0, 1)];
|
||||
assert_eq!(actual, expected)
|
||||
}
|
||||
}
|
||||
mod tests;
|
||||
|
128
crates/ide_db/src/line_index/tests.rs
Normal file
128
crates/ide_db/src/line_index/tests.rs
Normal file
@ -0,0 +1,128 @@
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_line_index() {
|
||||
let text = "hello\nworld";
|
||||
let index = LineIndex::new(text);
|
||||
assert_eq!(index.line_col(0.into()), LineCol { line: 0, col_utf16: 0 });
|
||||
assert_eq!(index.line_col(1.into()), LineCol { line: 0, col_utf16: 1 });
|
||||
assert_eq!(index.line_col(5.into()), LineCol { line: 0, col_utf16: 5 });
|
||||
assert_eq!(index.line_col(6.into()), LineCol { line: 1, col_utf16: 0 });
|
||||
assert_eq!(index.line_col(7.into()), LineCol { line: 1, col_utf16: 1 });
|
||||
assert_eq!(index.line_col(8.into()), LineCol { line: 1, col_utf16: 2 });
|
||||
assert_eq!(index.line_col(10.into()), LineCol { line: 1, col_utf16: 4 });
|
||||
assert_eq!(index.line_col(11.into()), LineCol { line: 1, col_utf16: 5 });
|
||||
assert_eq!(index.line_col(12.into()), LineCol { line: 1, col_utf16: 6 });
|
||||
|
||||
let text = "\nhello\nworld";
|
||||
let index = LineIndex::new(text);
|
||||
assert_eq!(index.line_col(0.into()), LineCol { line: 0, col_utf16: 0 });
|
||||
assert_eq!(index.line_col(1.into()), LineCol { line: 1, col_utf16: 0 });
|
||||
assert_eq!(index.line_col(2.into()), LineCol { line: 1, col_utf16: 1 });
|
||||
assert_eq!(index.line_col(6.into()), LineCol { line: 1, col_utf16: 5 });
|
||||
assert_eq!(index.line_col(7.into()), LineCol { line: 2, col_utf16: 0 });
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_char_len() {
|
||||
assert_eq!('メ'.len_utf8(), 3);
|
||||
assert_eq!('メ'.len_utf16(), 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_empty_index() {
|
||||
let col_index = LineIndex::new(
|
||||
"
|
||||
const C: char = 'x';
|
||||
",
|
||||
);
|
||||
assert_eq!(col_index.utf16_lines.len(), 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_single_char() {
|
||||
let col_index = LineIndex::new(
|
||||
"
|
||||
const C: char = 'メ';
|
||||
",
|
||||
);
|
||||
|
||||
assert_eq!(col_index.utf16_lines.len(), 1);
|
||||
assert_eq!(col_index.utf16_lines[&1].len(), 1);
|
||||
assert_eq!(col_index.utf16_lines[&1][0], Utf16Char { start: 17.into(), end: 20.into() });
|
||||
|
||||
// UTF-8 to UTF-16, no changes
|
||||
assert_eq!(col_index.utf8_to_utf16_col(1, 15.into()), 15);
|
||||
|
||||
// UTF-8 to UTF-16
|
||||
assert_eq!(col_index.utf8_to_utf16_col(1, 22.into()), 20);
|
||||
|
||||
// UTF-16 to UTF-8, no changes
|
||||
assert_eq!(col_index.utf16_to_utf8_col(1, 15), TextSize::from(15));
|
||||
|
||||
// UTF-16 to UTF-8
|
||||
assert_eq!(col_index.utf16_to_utf8_col(1, 19), TextSize::from(21));
|
||||
|
||||
let col_index = LineIndex::new("a𐐏b");
|
||||
assert_eq!(col_index.utf16_to_utf8_col(0, 3), TextSize::from(5));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_string() {
|
||||
let col_index = LineIndex::new(
|
||||
"
|
||||
const C: char = \"メ メ\";
|
||||
",
|
||||
);
|
||||
|
||||
assert_eq!(col_index.utf16_lines.len(), 1);
|
||||
assert_eq!(col_index.utf16_lines[&1].len(), 2);
|
||||
assert_eq!(col_index.utf16_lines[&1][0], Utf16Char { start: 17.into(), end: 20.into() });
|
||||
assert_eq!(col_index.utf16_lines[&1][1], Utf16Char { start: 21.into(), end: 24.into() });
|
||||
|
||||
// UTF-8 to UTF-16
|
||||
assert_eq!(col_index.utf8_to_utf16_col(1, 15.into()), 15);
|
||||
|
||||
assert_eq!(col_index.utf8_to_utf16_col(1, 21.into()), 19);
|
||||
assert_eq!(col_index.utf8_to_utf16_col(1, 25.into()), 21);
|
||||
|
||||
assert!(col_index.utf8_to_utf16_col(2, 15.into()) == 15);
|
||||
|
||||
// UTF-16 to UTF-8
|
||||
assert_eq!(col_index.utf16_to_utf8_col(1, 15), TextSize::from(15));
|
||||
|
||||
// メ UTF-8: 0xE3 0x83 0xA1, UTF-16: 0x30E1
|
||||
assert_eq!(col_index.utf16_to_utf8_col(1, 17), TextSize::from(17)); // first メ at 17..20
|
||||
assert_eq!(col_index.utf16_to_utf8_col(1, 18), TextSize::from(20)); // space
|
||||
assert_eq!(col_index.utf16_to_utf8_col(1, 19), TextSize::from(21)); // second メ at 21..24
|
||||
|
||||
assert_eq!(col_index.utf16_to_utf8_col(2, 15), TextSize::from(15));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_splitlines() {
|
||||
fn r(lo: u32, hi: u32) -> TextRange {
|
||||
TextRange::new(lo.into(), hi.into())
|
||||
}
|
||||
|
||||
let text = "a\nbb\nccc\n";
|
||||
let line_index = LineIndex::new(text);
|
||||
|
||||
let actual = line_index.lines(r(0, 9)).collect::<Vec<_>>();
|
||||
let expected = vec![r(0, 2), r(2, 5), r(5, 9)];
|
||||
assert_eq!(actual, expected);
|
||||
|
||||
let text = "";
|
||||
let line_index = LineIndex::new(text);
|
||||
|
||||
let actual = line_index.lines(r(0, 0)).collect::<Vec<_>>();
|
||||
let expected = vec![];
|
||||
assert_eq!(actual, expected);
|
||||
|
||||
let text = "\n";
|
||||
let line_index = LineIndex::new(text);
|
||||
|
||||
let actual = line_index.lines(r(0, 1)).collect::<Vec<_>>();
|
||||
let expected = vec![r(0, 1)];
|
||||
assert_eq!(actual, expected)
|
||||
}
|
@ -78,150 +78,4 @@ pub fn get_missing_assoc_items(
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::RootDatabase;
|
||||
use base_db::{fixture::ChangeFixture, FilePosition};
|
||||
use expect_test::{expect, Expect};
|
||||
use hir::Semantics;
|
||||
use syntax::ast::{self, AstNode};
|
||||
use test_utils::RangeOrOffset;
|
||||
|
||||
/// Creates analysis from a multi-file fixture, returns positions marked with <|>.
|
||||
pub(crate) fn position(ra_fixture: &str) -> (RootDatabase, FilePosition) {
|
||||
let change_fixture = ChangeFixture::parse(ra_fixture);
|
||||
let mut database = RootDatabase::default();
|
||||
database.apply_change(change_fixture.change);
|
||||
let (file_id, range_or_offset) =
|
||||
change_fixture.file_position.expect("expected a marker (<|>)");
|
||||
let offset = match range_or_offset {
|
||||
RangeOrOffset::Range(_) => panic!(),
|
||||
RangeOrOffset::Offset(it) => it,
|
||||
};
|
||||
(database, FilePosition { file_id, offset })
|
||||
}
|
||||
|
||||
fn check_trait(ra_fixture: &str, expect: Expect) {
|
||||
let (db, position) = position(ra_fixture);
|
||||
let sema = Semantics::new(&db);
|
||||
let file = sema.parse(position.file_id);
|
||||
let impl_block: ast::Impl =
|
||||
sema.find_node_at_offset_with_descend(file.syntax(), position.offset).unwrap();
|
||||
let trait_ = crate::traits::resolve_target_trait(&sema, &impl_block);
|
||||
let actual = match trait_ {
|
||||
Some(trait_) => trait_.name(&db).to_string(),
|
||||
None => String::new(),
|
||||
};
|
||||
expect.assert_eq(&actual);
|
||||
}
|
||||
|
||||
fn check_missing_assoc(ra_fixture: &str, expect: Expect) {
|
||||
let (db, position) = position(ra_fixture);
|
||||
let sema = Semantics::new(&db);
|
||||
let file = sema.parse(position.file_id);
|
||||
let impl_block: ast::Impl =
|
||||
sema.find_node_at_offset_with_descend(file.syntax(), position.offset).unwrap();
|
||||
let items = crate::traits::get_missing_assoc_items(&sema, &impl_block);
|
||||
let actual = items
|
||||
.into_iter()
|
||||
.map(|item| item.name(&db).unwrap().to_string())
|
||||
.collect::<Vec<_>>()
|
||||
.join("\n");
|
||||
expect.assert_eq(&actual);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn resolve_trait() {
|
||||
check_trait(
|
||||
r#"
|
||||
pub trait Foo {
|
||||
fn bar();
|
||||
}
|
||||
impl Foo for u8 {
|
||||
<|>
|
||||
}
|
||||
"#,
|
||||
expect![["Foo"]],
|
||||
);
|
||||
check_trait(
|
||||
r#"
|
||||
pub trait Foo {
|
||||
fn bar();
|
||||
}
|
||||
impl Foo for u8 {
|
||||
fn bar() {
|
||||
fn baz() {
|
||||
<|>
|
||||
}
|
||||
baz();
|
||||
}
|
||||
}
|
||||
"#,
|
||||
expect![["Foo"]],
|
||||
);
|
||||
check_trait(
|
||||
r#"
|
||||
pub trait Foo {
|
||||
fn bar();
|
||||
}
|
||||
pub struct Bar;
|
||||
impl Bar {
|
||||
<|>
|
||||
}
|
||||
"#,
|
||||
expect![[""]],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn missing_assoc_items() {
|
||||
check_missing_assoc(
|
||||
r#"
|
||||
pub trait Foo {
|
||||
const FOO: u8;
|
||||
fn bar();
|
||||
}
|
||||
impl Foo for u8 {
|
||||
<|>
|
||||
}"#,
|
||||
expect![[r#"
|
||||
FOO
|
||||
bar"#]],
|
||||
);
|
||||
|
||||
check_missing_assoc(
|
||||
r#"
|
||||
pub trait Foo {
|
||||
const FOO: u8;
|
||||
fn bar();
|
||||
}
|
||||
impl Foo for u8 {
|
||||
const FOO: u8 = 10;
|
||||
<|>
|
||||
}"#,
|
||||
expect![[r#"
|
||||
bar"#]],
|
||||
);
|
||||
|
||||
check_missing_assoc(
|
||||
r#"
|
||||
pub trait Foo {
|
||||
const FOO: u8;
|
||||
fn bar();
|
||||
}
|
||||
impl Foo for u8 {
|
||||
const FOO: u8 = 10;
|
||||
fn bar() {<|>}
|
||||
}"#,
|
||||
expect![[r#""#]],
|
||||
);
|
||||
|
||||
check_missing_assoc(
|
||||
r#"
|
||||
pub struct Foo;
|
||||
impl Foo {
|
||||
fn bar() {<|>}
|
||||
}"#,
|
||||
expect![[r#""#]],
|
||||
);
|
||||
}
|
||||
}
|
||||
mod tests;
|
||||
|
144
crates/ide_db/src/traits/tests.rs
Normal file
144
crates/ide_db/src/traits/tests.rs
Normal file
@ -0,0 +1,144 @@
|
||||
use crate::RootDatabase;
|
||||
use base_db::{fixture::ChangeFixture, FilePosition};
|
||||
use expect_test::{expect, Expect};
|
||||
use hir::Semantics;
|
||||
use syntax::ast::{self, AstNode};
|
||||
use test_utils::RangeOrOffset;
|
||||
|
||||
/// Creates analysis from a multi-file fixture, returns positions marked with <|>.
|
||||
pub(crate) fn position(ra_fixture: &str) -> (RootDatabase, FilePosition) {
|
||||
let change_fixture = ChangeFixture::parse(ra_fixture);
|
||||
let mut database = RootDatabase::default();
|
||||
database.apply_change(change_fixture.change);
|
||||
let (file_id, range_or_offset) = change_fixture.file_position.expect("expected a marker (<|>)");
|
||||
let offset = match range_or_offset {
|
||||
RangeOrOffset::Range(_) => panic!(),
|
||||
RangeOrOffset::Offset(it) => it,
|
||||
};
|
||||
(database, FilePosition { file_id, offset })
|
||||
}
|
||||
|
||||
fn check_trait(ra_fixture: &str, expect: Expect) {
|
||||
let (db, position) = position(ra_fixture);
|
||||
let sema = Semantics::new(&db);
|
||||
let file = sema.parse(position.file_id);
|
||||
let impl_block: ast::Impl =
|
||||
sema.find_node_at_offset_with_descend(file.syntax(), position.offset).unwrap();
|
||||
let trait_ = crate::traits::resolve_target_trait(&sema, &impl_block);
|
||||
let actual = match trait_ {
|
||||
Some(trait_) => trait_.name(&db).to_string(),
|
||||
None => String::new(),
|
||||
};
|
||||
expect.assert_eq(&actual);
|
||||
}
|
||||
|
||||
fn check_missing_assoc(ra_fixture: &str, expect: Expect) {
|
||||
let (db, position) = position(ra_fixture);
|
||||
let sema = Semantics::new(&db);
|
||||
let file = sema.parse(position.file_id);
|
||||
let impl_block: ast::Impl =
|
||||
sema.find_node_at_offset_with_descend(file.syntax(), position.offset).unwrap();
|
||||
let items = crate::traits::get_missing_assoc_items(&sema, &impl_block);
|
||||
let actual = items
|
||||
.into_iter()
|
||||
.map(|item| item.name(&db).unwrap().to_string())
|
||||
.collect::<Vec<_>>()
|
||||
.join("\n");
|
||||
expect.assert_eq(&actual);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn resolve_trait() {
|
||||
check_trait(
|
||||
r#"
|
||||
pub trait Foo {
|
||||
fn bar();
|
||||
}
|
||||
impl Foo for u8 {
|
||||
<|>
|
||||
}
|
||||
"#,
|
||||
expect![["Foo"]],
|
||||
);
|
||||
check_trait(
|
||||
r#"
|
||||
pub trait Foo {
|
||||
fn bar();
|
||||
}
|
||||
impl Foo for u8 {
|
||||
fn bar() {
|
||||
fn baz() {
|
||||
<|>
|
||||
}
|
||||
baz();
|
||||
}
|
||||
}
|
||||
"#,
|
||||
expect![["Foo"]],
|
||||
);
|
||||
check_trait(
|
||||
r#"
|
||||
pub trait Foo {
|
||||
fn bar();
|
||||
}
|
||||
pub struct Bar;
|
||||
impl Bar {
|
||||
<|>
|
||||
}
|
||||
"#,
|
||||
expect![[""]],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn missing_assoc_items() {
|
||||
check_missing_assoc(
|
||||
r#"
|
||||
pub trait Foo {
|
||||
const FOO: u8;
|
||||
fn bar();
|
||||
}
|
||||
impl Foo for u8 {
|
||||
<|>
|
||||
}"#,
|
||||
expect![[r#"
|
||||
FOO
|
||||
bar"#]],
|
||||
);
|
||||
|
||||
check_missing_assoc(
|
||||
r#"
|
||||
pub trait Foo {
|
||||
const FOO: u8;
|
||||
fn bar();
|
||||
}
|
||||
impl Foo for u8 {
|
||||
const FOO: u8 = 10;
|
||||
<|>
|
||||
}"#,
|
||||
expect![[r#"
|
||||
bar"#]],
|
||||
);
|
||||
|
||||
check_missing_assoc(
|
||||
r#"
|
||||
pub trait Foo {
|
||||
const FOO: u8;
|
||||
fn bar();
|
||||
}
|
||||
impl Foo for u8 {
|
||||
const FOO: u8 = 10;
|
||||
fn bar() {<|>}
|
||||
}"#,
|
||||
expect![[r#""#]],
|
||||
);
|
||||
|
||||
check_missing_assoc(
|
||||
r#"
|
||||
pub struct Foo;
|
||||
impl Foo {
|
||||
fn bar() {<|>}
|
||||
}"#,
|
||||
expect![[r#""#]],
|
||||
);
|
||||
}
|
Loading…
Reference in New Issue
Block a user