diff options
Diffstat (limited to 'crates')
79 files changed, 3511 insertions, 3187 deletions
diff --git a/crates/base_db/src/fixture.rs b/crates/base_db/src/fixture.rs index da4afb5eb..d56b20b83 100644 --- a/crates/base_db/src/fixture.rs +++ b/crates/base_db/src/fixture.rs | |||
@@ -9,8 +9,8 @@ use test_utils::{ | |||
9 | use vfs::{file_set::FileSet, VfsPath}; | 9 | use vfs::{file_set::FileSet, VfsPath}; |
10 | 10 | ||
11 | use crate::{ | 11 | use crate::{ |
12 | input::CrateName, Change, CrateGraph, CrateId, Edition, Env, FileId, FilePosition, FileRange, | 12 | input::CrateName, Change, CrateDisplayName, CrateGraph, CrateId, Edition, Env, FileId, |
13 | SourceDatabaseExt, SourceRoot, SourceRootId, | 13 | FilePosition, FileRange, SourceDatabaseExt, SourceRoot, SourceRootId, |
14 | }; | 14 | }; |
15 | 15 | ||
16 | pub const WORKSPACE: SourceRootId = SourceRootId(0); | 16 | pub const WORKSPACE: SourceRootId = SourceRootId(0); |
@@ -24,6 +24,14 @@ pub trait WithFixture: Default + SourceDatabaseExt + 'static { | |||
24 | (db, fixture.files[0]) | 24 | (db, fixture.files[0]) |
25 | } | 25 | } |
26 | 26 | ||
27 | fn with_many_files(ra_fixture: &str) -> (Self, Vec<FileId>) { | ||
28 | let fixture = ChangeFixture::parse(ra_fixture); | ||
29 | let mut db = Self::default(); | ||
30 | fixture.change.apply(&mut db); | ||
31 | assert!(fixture.file_position.is_none()); | ||
32 | (db, fixture.files) | ||
33 | } | ||
34 | |||
27 | fn with_files(ra_fixture: &str) -> Self { | 35 | fn with_files(ra_fixture: &str) -> Self { |
28 | let fixture = ChangeFixture::parse(ra_fixture); | 36 | let fixture = ChangeFixture::parse(ra_fixture); |
29 | let mut db = Self::default(); | 37 | let mut db = Self::default(); |
@@ -73,7 +81,7 @@ pub struct ChangeFixture { | |||
73 | 81 | ||
74 | impl ChangeFixture { | 82 | impl ChangeFixture { |
75 | pub fn parse(ra_fixture: &str) -> ChangeFixture { | 83 | pub fn parse(ra_fixture: &str) -> ChangeFixture { |
76 | let fixture = Fixture::parse(ra_fixture); | 84 | let (mini_core, fixture) = Fixture::parse(ra_fixture); |
77 | let mut change = Change::new(); | 85 | let mut change = Change::new(); |
78 | 86 | ||
79 | let mut files = Vec::new(); | 87 | let mut files = Vec::new(); |
@@ -158,6 +166,31 @@ impl ChangeFixture { | |||
158 | } | 166 | } |
159 | } | 167 | } |
160 | 168 | ||
169 | if let Some(mini_core) = mini_core { | ||
170 | let core_file = file_id; | ||
171 | file_id.0 += 1; | ||
172 | |||
173 | let mut fs = FileSet::default(); | ||
174 | fs.insert(core_file, VfsPath::new_virtual_path("/sysroot/core/lib.rs".to_string())); | ||
175 | roots.push(SourceRoot::new_library(fs)); | ||
176 | |||
177 | change.change_file(core_file, Some(Arc::new(mini_core.source_code()))); | ||
178 | |||
179 | let all_crates = crate_graph.crates_in_topological_order(); | ||
180 | |||
181 | let core_crate = crate_graph.add_crate_root( | ||
182 | core_file, | ||
183 | Edition::Edition2021, | ||
184 | Some(CrateDisplayName::from_canonical_name("core".to_string())), | ||
185 | CfgOptions::default(), | ||
186 | Env::default(), | ||
187 | Vec::new(), | ||
188 | ); | ||
189 | |||
190 | for krate in all_crates { | ||
191 | crate_graph.add_dep(krate, CrateName::new("core").unwrap(), core_crate).unwrap(); | ||
192 | } | ||
193 | } | ||
161 | roots.push(SourceRoot::new_local(mem::take(&mut file_set))); | 194 | roots.push(SourceRoot::new_local(mem::take(&mut file_set))); |
162 | change.set_roots(roots); | 195 | change.set_roots(roots); |
163 | change.set_crate_graph(crate_graph); | 196 | change.set_crate_graph(crate_graph); |
diff --git a/crates/hir/src/has_source.rs b/crates/hir/src/has_source.rs index dc10a4d0f..197149c5e 100644 --- a/crates/hir/src/has_source.rs +++ b/crates/hir/src/has_source.rs | |||
@@ -127,7 +127,7 @@ impl HasSource for Impl { | |||
127 | } | 127 | } |
128 | 128 | ||
129 | impl HasSource for TypeParam { | 129 | impl HasSource for TypeParam { |
130 | type Ast = Either<ast::Trait, ast::TypeParam>; | 130 | type Ast = Either<ast::TypeParam, ast::Trait>; |
131 | fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> { | 131 | fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> { |
132 | let child_source = self.id.parent.child_source(db.upcast()); | 132 | let child_source = self.id.parent.child_source(db.upcast()); |
133 | Some(child_source.map(|it| it[self.id.local_id].clone())) | 133 | Some(child_source.map(|it| it[self.id.local_id].clone())) |
diff --git a/crates/hir_def/src/generics.rs b/crates/hir_def/src/generics.rs index 6933f6e3c..0f04b2bae 100644 --- a/crates/hir_def/src/generics.rs +++ b/crates/hir_def/src/generics.rs | |||
@@ -92,7 +92,7 @@ pub enum WherePredicateTypeTarget { | |||
92 | 92 | ||
93 | #[derive(Default)] | 93 | #[derive(Default)] |
94 | pub(crate) struct SourceMap { | 94 | pub(crate) struct SourceMap { |
95 | pub(crate) type_params: ArenaMap<LocalTypeParamId, Either<ast::Trait, ast::TypeParam>>, | 95 | pub(crate) type_params: ArenaMap<LocalTypeParamId, Either<ast::TypeParam, ast::Trait>>, |
96 | lifetime_params: ArenaMap<LocalLifetimeParamId, ast::LifetimeParam>, | 96 | lifetime_params: ArenaMap<LocalLifetimeParamId, ast::LifetimeParam>, |
97 | const_params: ArenaMap<LocalConstParamId, ast::ConstParam>, | 97 | const_params: ArenaMap<LocalConstParamId, ast::ConstParam>, |
98 | } | 98 | } |
@@ -199,7 +199,7 @@ impl GenericParams { | |||
199 | default: None, | 199 | default: None, |
200 | provenance: TypeParamProvenance::TraitSelf, | 200 | provenance: TypeParamProvenance::TraitSelf, |
201 | }); | 201 | }); |
202 | sm.type_params.insert(self_param_id, Either::Left(src.value.clone())); | 202 | sm.type_params.insert(self_param_id, Either::Right(src.value.clone())); |
203 | // add super traits as bounds on Self | 203 | // add super traits as bounds on Self |
204 | // i.e., trait Foo: Bar is equivalent to trait Foo where Self: Bar | 204 | // i.e., trait Foo: Bar is equivalent to trait Foo where Self: Bar |
205 | let self_param = TypeRef::Path(name![Self].into()); | 205 | let self_param = TypeRef::Path(name![Self].into()); |
@@ -277,7 +277,7 @@ impl GenericParams { | |||
277 | provenance: TypeParamProvenance::TypeParamList, | 277 | provenance: TypeParamProvenance::TypeParamList, |
278 | }; | 278 | }; |
279 | let param_id = self.types.alloc(param); | 279 | let param_id = self.types.alloc(param); |
280 | sm.type_params.insert(param_id, Either::Right(type_param.clone())); | 280 | sm.type_params.insert(param_id, Either::Left(type_param.clone())); |
281 | 281 | ||
282 | let type_ref = TypeRef::Path(name.into()); | 282 | let type_ref = TypeRef::Path(name.into()); |
283 | self.fill_bounds(lower_ctx, &type_param, Either::Left(type_ref)); | 283 | self.fill_bounds(lower_ctx, &type_param, Either::Left(type_ref)); |
@@ -413,7 +413,7 @@ impl GenericParams { | |||
413 | } | 413 | } |
414 | 414 | ||
415 | impl HasChildSource<LocalTypeParamId> for GenericDefId { | 415 | impl HasChildSource<LocalTypeParamId> for GenericDefId { |
416 | type Value = Either<ast::Trait, ast::TypeParam>; | 416 | type Value = Either<ast::TypeParam, ast::Trait>; |
417 | fn child_source( | 417 | fn child_source( |
418 | &self, | 418 | &self, |
419 | db: &dyn DefDatabase, | 419 | db: &dyn DefDatabase, |
@@ -449,7 +449,7 @@ impl ChildBySource for GenericDefId { | |||
449 | let sm = sm.as_ref(); | 449 | let sm = sm.as_ref(); |
450 | for (local_id, src) in sm.value.type_params.iter() { | 450 | for (local_id, src) in sm.value.type_params.iter() { |
451 | let id = TypeParamId { parent: *self, local_id }; | 451 | let id = TypeParamId { parent: *self, local_id }; |
452 | if let Either::Right(type_param) = src { | 452 | if let Either::Left(type_param) = src { |
453 | res[keys::TYPE_PARAM].insert(sm.with_value(type_param.clone()), id) | 453 | res[keys::TYPE_PARAM].insert(sm.with_value(type_param.clone()), id) |
454 | } | 454 | } |
455 | } | 455 | } |
diff --git a/crates/hir_def/src/item_tree/lower.rs b/crates/hir_def/src/item_tree/lower.rs index 3f90bda74..5b1386406 100644 --- a/crates/hir_def/src/item_tree/lower.rs +++ b/crates/hir_def/src/item_tree/lower.rs | |||
@@ -674,7 +674,7 @@ impl<'a> Ctx<'a> { | |||
674 | default: None, | 674 | default: None, |
675 | provenance: TypeParamProvenance::TraitSelf, | 675 | provenance: TypeParamProvenance::TraitSelf, |
676 | }); | 676 | }); |
677 | sm.type_params.insert(self_param_id, Either::Left(trait_def.clone())); | 677 | sm.type_params.insert(self_param_id, Either::Right(trait_def.clone())); |
678 | // add super traits as bounds on Self | 678 | // add super traits as bounds on Self |
679 | // i.e., trait Foo: Bar is equivalent to trait Foo where Self: Bar | 679 | // i.e., trait Foo: Bar is equivalent to trait Foo where Self: Bar |
680 | let self_param = TypeRef::Path(name![Self].into()); | 680 | let self_param = TypeRef::Path(name![Self].into()); |
diff --git a/crates/hir_def/src/nameres/collector.rs b/crates/hir_def/src/nameres/collector.rs index 6fab58f15..fc2c50fb8 100644 --- a/crates/hir_def/src/nameres/collector.rs +++ b/crates/hir_def/src/nameres/collector.rs | |||
@@ -1992,8 +1992,8 @@ mod tests { | |||
1992 | collector.def_map | 1992 | collector.def_map |
1993 | } | 1993 | } |
1994 | 1994 | ||
1995 | fn do_resolve(code: &str) -> DefMap { | 1995 | fn do_resolve(not_ra_fixture: &str) -> DefMap { |
1996 | let (db, _file_id) = TestDB::with_single_file(code); | 1996 | let (db, _file_id) = TestDB::with_single_file(not_ra_fixture); |
1997 | let krate = db.test_crate(); | 1997 | let krate = db.test_crate(); |
1998 | 1998 | ||
1999 | let edition = db.crate_graph()[krate].edition; | 1999 | let edition = db.crate_graph()[krate].edition; |
@@ -2005,24 +2005,37 @@ mod tests { | |||
2005 | fn test_macro_expand_will_stop_1() { | 2005 | fn test_macro_expand_will_stop_1() { |
2006 | do_resolve( | 2006 | do_resolve( |
2007 | r#" | 2007 | r#" |
2008 | macro_rules! foo { | 2008 | macro_rules! foo { |
2009 | ($($ty:ty)*) => { foo!($($ty)*); } | 2009 | ($($ty:ty)*) => { foo!($($ty)*); } |
2010 | } | 2010 | } |
2011 | foo!(KABOOM); | 2011 | foo!(KABOOM); |
2012 | "#, | 2012 | "#, |
2013 | ); | ||
2014 | do_resolve( | ||
2015 | r#" | ||
2016 | macro_rules! foo { | ||
2017 | ($($ty:ty)*) => { foo!(() $($ty)*); } | ||
2018 | } | ||
2019 | foo!(KABOOM); | ||
2020 | "#, | ||
2013 | ); | 2021 | ); |
2014 | } | 2022 | } |
2015 | 2023 | ||
2016 | #[ignore] // this test does succeed, but takes quite a while :/ | 2024 | #[ignore] |
2017 | #[test] | 2025 | #[test] |
2018 | fn test_macro_expand_will_stop_2() { | 2026 | fn test_macro_expand_will_stop_2() { |
2027 | // FIXME: this test does succeed, but takes quite a while: 90 seconds in | ||
2028 | // the release mode. That's why the argument is not an ra_fixture -- | ||
2029 | // otherwise injection highlighting gets stuck. | ||
2030 | // | ||
2031 | // We need to find a way to fail this faster. | ||
2019 | do_resolve( | 2032 | do_resolve( |
2020 | r#" | 2033 | r#" |
2021 | macro_rules! foo { | 2034 | macro_rules! foo { |
2022 | ($($ty:ty)*) => { foo!($($ty)* $($ty)*); } | 2035 | ($($ty:ty)*) => { foo!($($ty)* $($ty)*); } |
2023 | } | 2036 | } |
2024 | foo!(KABOOM); | 2037 | foo!(KABOOM); |
2025 | "#, | 2038 | "#, |
2026 | ); | 2039 | ); |
2027 | } | 2040 | } |
2028 | } | 2041 | } |
diff --git a/crates/hir_ty/Cargo.toml b/crates/hir_ty/Cargo.toml index a1894e8d8..74129eb21 100644 --- a/crates/hir_ty/Cargo.toml +++ b/crates/hir_ty/Cargo.toml | |||
@@ -20,7 +20,7 @@ rustc-hash = "1.1.0" | |||
20 | scoped-tls = "1" | 20 | scoped-tls = "1" |
21 | chalk-solve = { version = "0.68", default-features = false } | 21 | chalk-solve = { version = "0.68", default-features = false } |
22 | chalk-ir = "0.68" | 22 | chalk-ir = "0.68" |
23 | chalk-recursive = "0.68" | 23 | chalk-recursive = { version = "0.68", default-features = false } |
24 | la-arena = { version = "0.2.0", path = "../../lib/arena" } | 24 | la-arena = { version = "0.2.0", path = "../../lib/arena" } |
25 | once_cell = { version = "1.5.0" } | 25 | once_cell = { version = "1.5.0" } |
26 | 26 | ||
diff --git a/crates/hir_ty/src/tests/coercion.rs b/crates/hir_ty/src/tests/coercion.rs index 71047703d..713b74165 100644 --- a/crates/hir_ty/src/tests/coercion.rs +++ b/crates/hir_ty/src/tests/coercion.rs | |||
@@ -23,38 +23,29 @@ fn infer_block_expr_type_mismatch() { | |||
23 | fn coerce_places() { | 23 | fn coerce_places() { |
24 | check_infer( | 24 | check_infer( |
25 | r#" | 25 | r#" |
26 | struct S<T> { a: T } | 26 | //- minicore: coerce_unsized |
27 | struct S<T> { a: T } | ||
27 | 28 | ||
28 | fn f<T>(_: &[T]) -> T { loop {} } | 29 | fn f<T>(_: &[T]) -> T { loop {} } |
29 | fn g<T>(_: S<&[T]>) -> T { loop {} } | 30 | fn g<T>(_: S<&[T]>) -> T { loop {} } |
30 | 31 | ||
31 | fn gen<T>() -> *mut [T; 2] { loop {} } | 32 | fn gen<T>() -> *mut [T; 2] { loop {} } |
32 | fn test1<U>() -> *mut [U] { | 33 | fn test1<U>() -> *mut [U] { |
33 | gen() | 34 | gen() |
34 | } | 35 | } |
35 | |||
36 | fn test2() { | ||
37 | let arr: &[u8; 1] = &[1]; | ||
38 | |||
39 | let a: &[_] = arr; | ||
40 | let b = f(arr); | ||
41 | let c: &[_] = { arr }; | ||
42 | let d = g(S { a: arr }); | ||
43 | let e: [&[_]; 1] = [arr]; | ||
44 | let f: [&[_]; 2] = [arr; 2]; | ||
45 | let g: (&[_], &[_]) = (arr, arr); | ||
46 | } | ||
47 | 36 | ||
48 | #[lang = "sized"] | 37 | fn test2() { |
49 | pub trait Sized {} | 38 | let arr: &[u8; 1] = &[1]; |
50 | #[lang = "unsize"] | ||
51 | pub trait Unsize<T: ?Sized> {} | ||
52 | #[lang = "coerce_unsized"] | ||
53 | pub trait CoerceUnsized<T> {} | ||
54 | 39 | ||
55 | impl<'a, 'b: 'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a U> for &'b T {} | 40 | let a: &[_] = arr; |
56 | impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*mut U> for *mut T {} | 41 | let b = f(arr); |
57 | "#, | 42 | let c: &[_] = { arr }; |
43 | let d = g(S { a: arr }); | ||
44 | let e: [&[_]; 1] = [arr]; | ||
45 | let f: [&[_]; 2] = [arr; 2]; | ||
46 | let g: (&[_], &[_]) = (arr, arr); | ||
47 | } | ||
48 | "#, | ||
58 | expect![[r#" | 49 | expect![[r#" |
59 | 30..31 '_': &[T] | 50 | 30..31 '_': &[T] |
60 | 44..55 '{ loop {} }': T | 51 | 44..55 '{ loop {} }': T |
@@ -131,60 +122,52 @@ fn infer_let_stmt_coerce() { | |||
131 | fn infer_custom_coerce_unsized() { | 122 | fn infer_custom_coerce_unsized() { |
132 | check_infer( | 123 | check_infer( |
133 | r#" | 124 | r#" |
134 | struct A<T: ?Sized>(*const T); | 125 | //- minicore: coerce_unsized |
135 | struct B<T: ?Sized>(*const T); | 126 | use core::{marker::Unsize, ops::CoerceUnsized}; |
136 | struct C<T: ?Sized> { inner: *const T } | ||
137 | 127 | ||
138 | impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<B<U>> for B<T> {} | 128 | struct A<T: ?Sized>(*const T); |
139 | impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<C<U>> for C<T> {} | 129 | struct B<T: ?Sized>(*const T); |
130 | struct C<T: ?Sized> { inner: *const T } | ||
140 | 131 | ||
141 | fn foo1<T>(x: A<[T]>) -> A<[T]> { x } | 132 | impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<B<U>> for B<T> {} |
142 | fn foo2<T>(x: B<[T]>) -> B<[T]> { x } | 133 | impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<C<U>> for C<T> {} |
143 | fn foo3<T>(x: C<[T]>) -> C<[T]> { x } | ||
144 | 134 | ||
145 | fn test(a: A<[u8; 2]>, b: B<[u8; 2]>, c: C<[u8; 2]>) { | 135 | fn foo1<T>(x: A<[T]>) -> A<[T]> { x } |
146 | let d = foo1(a); | 136 | fn foo2<T>(x: B<[T]>) -> B<[T]> { x } |
147 | let e = foo2(b); | 137 | fn foo3<T>(x: C<[T]>) -> C<[T]> { x } |
148 | let f = foo3(c); | ||
149 | } | ||
150 | |||
151 | |||
152 | #[lang = "sized"] | ||
153 | pub trait Sized {} | ||
154 | #[lang = "unsize"] | ||
155 | pub trait Unsize<T: ?Sized> {} | ||
156 | #[lang = "coerce_unsized"] | ||
157 | pub trait CoerceUnsized<T> {} | ||
158 | 138 | ||
159 | impl<'a, 'b: 'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a U> for &'b T {} | 139 | fn test(a: A<[u8; 2]>, b: B<[u8; 2]>, c: C<[u8; 2]>) { |
160 | impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*mut U> for *mut T {} | 140 | let d = foo1(a); |
161 | "#, | 141 | let e = foo2(b); |
142 | let f = foo3(c); | ||
143 | } | ||
144 | "#, | ||
162 | expect![[r#" | 145 | expect![[r#" |
163 | 257..258 'x': A<[T]> | 146 | 306..307 'x': A<[T]> |
164 | 278..283 '{ x }': A<[T]> | 147 | 327..332 '{ x }': A<[T]> |
165 | 280..281 'x': A<[T]> | 148 | 329..330 'x': A<[T]> |
166 | 295..296 'x': B<[T]> | 149 | 344..345 'x': B<[T]> |
167 | 316..321 '{ x }': B<[T]> | 150 | 365..370 '{ x }': B<[T]> |
168 | 318..319 'x': B<[T]> | 151 | 367..368 'x': B<[T]> |
169 | 333..334 'x': C<[T]> | 152 | 382..383 'x': C<[T]> |
170 | 354..359 '{ x }': C<[T]> | 153 | 403..408 '{ x }': C<[T]> |
171 | 356..357 'x': C<[T]> | 154 | 405..406 'x': C<[T]> |
172 | 369..370 'a': A<[u8; 2]> | 155 | 418..419 'a': A<[u8; 2]> |
173 | 384..385 'b': B<[u8; 2]> | 156 | 433..434 'b': B<[u8; 2]> |
174 | 399..400 'c': C<[u8; 2]> | 157 | 448..449 'c': C<[u8; 2]> |
175 | 414..480 '{ ...(c); }': () | 158 | 463..529 '{ ...(c); }': () |
176 | 424..425 'd': A<[{unknown}]> | 159 | 473..474 'd': A<[{unknown}]> |
177 | 428..432 'foo1': fn foo1<{unknown}>(A<[{unknown}]>) -> A<[{unknown}]> | 160 | 477..481 'foo1': fn foo1<{unknown}>(A<[{unknown}]>) -> A<[{unknown}]> |
178 | 428..435 'foo1(a)': A<[{unknown}]> | 161 | 477..484 'foo1(a)': A<[{unknown}]> |
179 | 433..434 'a': A<[u8; 2]> | 162 | 482..483 'a': A<[u8; 2]> |
180 | 445..446 'e': B<[u8]> | 163 | 494..495 'e': B<[u8]> |
181 | 449..453 'foo2': fn foo2<u8>(B<[u8]>) -> B<[u8]> | 164 | 498..502 'foo2': fn foo2<u8>(B<[u8]>) -> B<[u8]> |
182 | 449..456 'foo2(b)': B<[u8]> | 165 | 498..505 'foo2(b)': B<[u8]> |
183 | 454..455 'b': B<[u8; 2]> | 166 | 503..504 'b': B<[u8; 2]> |
184 | 466..467 'f': C<[u8]> | 167 | 515..516 'f': C<[u8]> |
185 | 470..474 'foo3': fn foo3<u8>(C<[u8]>) -> C<[u8]> | 168 | 519..523 'foo3': fn foo3<u8>(C<[u8]>) -> C<[u8]> |
186 | 470..477 'foo3(c)': C<[u8]> | 169 | 519..526 'foo3(c)': C<[u8]> |
187 | 475..476 'c': C<[u8; 2]> | 170 | 524..525 'c': C<[u8; 2]> |
188 | "#]], | 171 | "#]], |
189 | ); | 172 | ); |
190 | } | 173 | } |
@@ -193,21 +176,16 @@ fn infer_custom_coerce_unsized() { | |||
193 | fn infer_if_coerce() { | 176 | fn infer_if_coerce() { |
194 | check_infer( | 177 | check_infer( |
195 | r#" | 178 | r#" |
196 | fn foo<T>(x: &[T]) -> &[T] { loop {} } | 179 | //- minicore: unsize |
197 | fn test() { | 180 | fn foo<T>(x: &[T]) -> &[T] { loop {} } |
198 | let x = if true { | 181 | fn test() { |
199 | foo(&[1]) | 182 | let x = if true { |
200 | } else { | 183 | foo(&[1]) |
201 | &[1] | 184 | } else { |
202 | }; | 185 | &[1] |
203 | } | 186 | }; |
204 | 187 | } | |
205 | 188 | "#, | |
206 | #[lang = "sized"] | ||
207 | pub trait Sized {} | ||
208 | #[lang = "unsize"] | ||
209 | pub trait Unsize<T: ?Sized> {} | ||
210 | "#, | ||
211 | expect![[r#" | 189 | expect![[r#" |
212 | 10..11 'x': &[T] | 190 | 10..11 'x': &[T] |
213 | 27..38 '{ loop {} }': &[T] | 191 | 27..38 '{ loop {} }': &[T] |
@@ -235,25 +213,16 @@ fn infer_if_coerce() { | |||
235 | fn infer_if_else_coerce() { | 213 | fn infer_if_else_coerce() { |
236 | check_infer( | 214 | check_infer( |
237 | r#" | 215 | r#" |
238 | fn foo<T>(x: &[T]) -> &[T] { loop {} } | 216 | //- minicore: coerce_unsized |
239 | fn test() { | 217 | fn foo<T>(x: &[T]) -> &[T] { loop {} } |
240 | let x = if true { | 218 | fn test() { |
241 | &[1] | 219 | let x = if true { |
242 | } else { | 220 | &[1] |
243 | foo(&[1]) | 221 | } else { |
244 | }; | 222 | foo(&[1]) |
245 | } | 223 | }; |
246 | 224 | } | |
247 | #[lang = "sized"] | 225 | "#, |
248 | pub trait Sized {} | ||
249 | #[lang = "unsize"] | ||
250 | pub trait Unsize<T: ?Sized> {} | ||
251 | #[lang = "coerce_unsized"] | ||
252 | pub trait CoerceUnsized<T> {} | ||
253 | |||
254 | impl<'a, 'b: 'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a U> for &'b T {} | ||
255 | impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*mut U> for *mut T {} | ||
256 | "#, | ||
257 | expect![[r#" | 226 | expect![[r#" |
258 | 10..11 'x': &[T] | 227 | 10..11 'x': &[T] |
259 | 27..38 '{ loop {} }': &[T] | 228 | 27..38 '{ loop {} }': &[T] |
@@ -281,20 +250,16 @@ fn infer_if_else_coerce() { | |||
281 | fn infer_match_first_coerce() { | 250 | fn infer_match_first_coerce() { |
282 | check_infer( | 251 | check_infer( |
283 | r#" | 252 | r#" |
284 | fn foo<T>(x: &[T]) -> &[T] { loop {} } | 253 | //- minicore: unsize |
285 | fn test(i: i32) { | 254 | fn foo<T>(x: &[T]) -> &[T] { loop {} } |
286 | let x = match i { | 255 | fn test(i: i32) { |
287 | 2 => foo(&[2]), | 256 | let x = match i { |
288 | 1 => &[1], | 257 | 2 => foo(&[2]), |
289 | _ => &[3], | 258 | 1 => &[1], |
290 | }; | 259 | _ => &[3], |
291 | } | 260 | }; |
292 | 261 | } | |
293 | #[lang = "sized"] | 262 | "#, |
294 | pub trait Sized {} | ||
295 | #[lang = "unsize"] | ||
296 | pub trait Unsize<T: ?Sized> {} | ||
297 | "#, | ||
298 | expect![[r#" | 263 | expect![[r#" |
299 | 10..11 'x': &[T] | 264 | 10..11 'x': &[T] |
300 | 27..38 '{ loop {} }': &[T] | 265 | 27..38 '{ loop {} }': &[T] |
@@ -329,25 +294,16 @@ fn infer_match_first_coerce() { | |||
329 | fn infer_match_second_coerce() { | 294 | fn infer_match_second_coerce() { |
330 | check_infer( | 295 | check_infer( |
331 | r#" | 296 | r#" |
332 | fn foo<T>(x: &[T]) -> &[T] { loop {} } | 297 | //- minicore: coerce_unsized |
333 | fn test(i: i32) { | 298 | fn foo<T>(x: &[T]) -> &[T] { loop {} } |
334 | let x = match i { | 299 | fn test(i: i32) { |
335 | 1 => &[1], | 300 | let x = match i { |
336 | 2 => foo(&[2]), | 301 | 1 => &[1], |
337 | _ => &[3], | 302 | 2 => foo(&[2]), |
338 | }; | 303 | _ => &[3], |
339 | } | 304 | }; |
340 | 305 | } | |
341 | #[lang = "sized"] | 306 | "#, |
342 | pub trait Sized {} | ||
343 | #[lang = "unsize"] | ||
344 | pub trait Unsize<T: ?Sized> {} | ||
345 | #[lang = "coerce_unsized"] | ||
346 | pub trait CoerceUnsized<T> {} | ||
347 | |||
348 | impl<'a, 'b: 'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a U> for &'b T {} | ||
349 | impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*mut U> for *mut T {} | ||
350 | "#, | ||
351 | expect![[r#" | 307 | expect![[r#" |
352 | 10..11 'x': &[T] | 308 | 10..11 'x': &[T] |
353 | 27..38 '{ loop {} }': &[T] | 309 | 27..38 '{ loop {} }': &[T] |
@@ -470,15 +426,15 @@ fn coerce_autoderef() { | |||
470 | #[test] | 426 | #[test] |
471 | fn coerce_autoderef_generic() { | 427 | fn coerce_autoderef_generic() { |
472 | check_infer_with_mismatches( | 428 | check_infer_with_mismatches( |
473 | r" | 429 | r#" |
474 | struct Foo; | 430 | struct Foo; |
475 | fn takes_ref<T>(x: &T) -> T { *x } | 431 | fn takes_ref<T>(x: &T) -> T { *x } |
476 | fn test() { | 432 | fn test() { |
477 | takes_ref(&Foo); | 433 | takes_ref(&Foo); |
478 | takes_ref(&&Foo); | 434 | takes_ref(&&Foo); |
479 | takes_ref(&&&Foo); | 435 | takes_ref(&&&Foo); |
480 | } | 436 | } |
481 | ", | 437 | "#, |
482 | expect![[r" | 438 | expect![[r" |
483 | 28..29 'x': &T | 439 | 28..29 'x': &T |
484 | 40..46 '{ *x }': T | 440 | 40..46 '{ *x }': T |
@@ -508,30 +464,29 @@ fn coerce_autoderef_generic() { | |||
508 | fn coerce_autoderef_block() { | 464 | fn coerce_autoderef_block() { |
509 | check_infer_with_mismatches( | 465 | check_infer_with_mismatches( |
510 | r#" | 466 | r#" |
511 | struct String {} | 467 | //- minicore: deref |
512 | #[lang = "deref"] | 468 | struct String {} |
513 | trait Deref { type Target; } | 469 | impl core::ops::Deref for String { type Target = str; } |
514 | impl Deref for String { type Target = str; } | 470 | fn takes_ref_str(x: &str) {} |
515 | fn takes_ref_str(x: &str) {} | 471 | fn returns_string() -> String { loop {} } |
516 | fn returns_string() -> String { loop {} } | 472 | fn test() { |
517 | fn test() { | 473 | takes_ref_str(&{ returns_string() }); |
518 | takes_ref_str(&{ returns_string() }); | 474 | } |
519 | } | 475 | "#, |
520 | "#, | 476 | expect![[r#" |
521 | expect![[r" | 477 | 90..91 'x': &str |
522 | 126..127 'x': &str | 478 | 99..101 '{}': () |
523 | 135..137 '{}': () | 479 | 132..143 '{ loop {} }': String |
524 | 168..179 '{ loop {} }': String | 480 | 134..141 'loop {}': ! |
525 | 170..177 'loop {}': ! | 481 | 139..141 '{}': () |
526 | 175..177 '{}': () | 482 | 154..199 '{ ... }); }': () |
527 | 190..235 '{ ... }); }': () | 483 | 160..173 'takes_ref_str': fn takes_ref_str(&str) |
528 | 196..209 'takes_ref_str': fn takes_ref_str(&str) | 484 | 160..196 'takes_...g() })': () |
529 | 196..232 'takes_...g() })': () | 485 | 174..195 '&{ ret...ng() }': &String |
530 | 210..231 '&{ ret...ng() }': &String | 486 | 175..195 '{ retu...ng() }': String |
531 | 211..231 '{ retu...ng() }': String | 487 | 177..191 'returns_string': fn returns_string() -> String |
532 | 213..227 'returns_string': fn returns_string() -> String | 488 | 177..193 'return...ring()': String |
533 | 213..229 'return...ring()': String | 489 | "#]], |
534 | "]], | ||
535 | ); | 490 | ); |
536 | } | 491 | } |
537 | 492 | ||
@@ -674,25 +629,19 @@ fn coerce_placeholder_ref() { | |||
674 | fn coerce_unsize_array() { | 629 | fn coerce_unsize_array() { |
675 | check_infer_with_mismatches( | 630 | check_infer_with_mismatches( |
676 | r#" | 631 | r#" |
677 | #[lang = "unsize"] | 632 | //- minicore: coerce_unsized |
678 | pub trait Unsize<T> {} | 633 | fn test() { |
679 | #[lang = "coerce_unsized"] | 634 | let f: &[usize] = &[1, 2, 3]; |
680 | pub trait CoerceUnsized<T> {} | 635 | } |
681 | |||
682 | impl<T: Unsize<U>, U> CoerceUnsized<&U> for &T {} | ||
683 | |||
684 | fn test() { | ||
685 | let f: &[usize] = &[1, 2, 3]; | ||
686 | } | ||
687 | "#, | 636 | "#, |
688 | expect![[r#" | 637 | expect![[r#" |
689 | 161..198 '{ ... 3]; }': () | 638 | 10..47 '{ ... 3]; }': () |
690 | 171..172 'f': &[usize] | 639 | 20..21 'f': &[usize] |
691 | 185..195 '&[1, 2, 3]': &[usize; 3] | 640 | 34..44 '&[1, 2, 3]': &[usize; 3] |
692 | 186..195 '[1, 2, 3]': [usize; 3] | 641 | 35..44 '[1, 2, 3]': [usize; 3] |
693 | 187..188 '1': usize | 642 | 36..37 '1': usize |
694 | 190..191 '2': usize | 643 | 39..40 '2': usize |
695 | 193..194 '3': usize | 644 | 42..43 '3': usize |
696 | "#]], | 645 | "#]], |
697 | ); | 646 | ); |
698 | } | 647 | } |
@@ -701,93 +650,94 @@ fn coerce_unsize_array() { | |||
701 | fn coerce_unsize_trait_object_simple() { | 650 | fn coerce_unsize_trait_object_simple() { |
702 | check_infer_with_mismatches( | 651 | check_infer_with_mismatches( |
703 | r#" | 652 | r#" |
704 | #[lang = "sized"] | 653 | //- minicore: coerce_unsized |
705 | pub trait Sized {} | 654 | trait Foo<T, U> {} |
706 | #[lang = "unsize"] | 655 | trait Bar<U, T, X>: Foo<T, U> {} |
707 | pub trait Unsize<T> {} | 656 | trait Baz<T, X>: Bar<usize, T, X> {} |
708 | #[lang = "coerce_unsized"] | 657 | |
709 | pub trait CoerceUnsized<T> {} | 658 | struct S<T, X>; |
710 | 659 | impl<T, X> Foo<T, usize> for S<T, X> {} | |
711 | impl<T: Unsize<U>, U> CoerceUnsized<&U> for &T {} | 660 | impl<T, X> Bar<usize, T, X> for S<T, X> {} |
712 | 661 | impl<T, X> Baz<T, X> for S<T, X> {} | |
713 | trait Foo<T, U> {} | 662 | |
714 | trait Bar<U, T, X>: Foo<T, U> {} | 663 | fn test() { |
715 | trait Baz<T, X>: Bar<usize, T, X> {} | 664 | let obj: &dyn Baz<i8, i16> = &S; |
716 | 665 | let obj: &dyn Bar<_, i8, i16> = &S; | |
717 | struct S<T, X>; | 666 | let obj: &dyn Foo<i8, _> = &S; |
718 | impl<T, X> Foo<T, usize> for S<T, X> {} | 667 | } |
719 | impl<T, X> Bar<usize, T, X> for S<T, X> {} | 668 | "#, |
720 | impl<T, X> Baz<T, X> for S<T, X> {} | 669 | expect![[r#" |
721 | 670 | 236..351 '{ ... &S; }': () | |
722 | fn test() { | 671 | 246..249 'obj': &dyn Baz<i8, i16> |
723 | let obj: &dyn Baz<i8, i16> = &S; | 672 | 271..273 '&S': &S<i8, i16> |
724 | let obj: &dyn Bar<_, i8, i16> = &S; | 673 | 272..273 'S': S<i8, i16> |
725 | let obj: &dyn Foo<i8, _> = &S; | 674 | 283..286 'obj': &dyn Bar<usize, i8, i16> |
726 | } | 675 | 311..313 '&S': &S<i8, i16> |
727 | "#, | 676 | 312..313 'S': S<i8, i16> |
728 | expect![[r" | 677 | 323..326 'obj': &dyn Foo<i8, usize> |
729 | 424..539 '{ ... &S; }': () | 678 | 346..348 '&S': &S<i8, {unknown}> |
730 | 434..437 'obj': &dyn Baz<i8, i16> | 679 | 347..348 'S': S<i8, {unknown}> |
731 | 459..461 '&S': &S<i8, i16> | 680 | "#]], |
732 | 460..461 'S': S<i8, i16> | ||
733 | 471..474 'obj': &dyn Bar<usize, i8, i16> | ||
734 | 499..501 '&S': &S<i8, i16> | ||
735 | 500..501 'S': S<i8, i16> | ||
736 | 511..514 'obj': &dyn Foo<i8, usize> | ||
737 | 534..536 '&S': &S<i8, {unknown}> | ||
738 | 535..536 'S': S<i8, {unknown}> | ||
739 | "]], | ||
740 | ); | 681 | ); |
741 | } | 682 | } |
742 | 683 | ||
743 | #[test] | 684 | #[test] |
744 | // The rust reference says this should be possible, but rustc doesn't implement | ||
745 | // it. We used to support it, but Chalk doesn't. | ||
746 | #[ignore] | ||
747 | fn coerce_unsize_trait_object_to_trait_object() { | 685 | fn coerce_unsize_trait_object_to_trait_object() { |
686 | // FIXME: The rust reference says this should be possible, but rustc doesn't | ||
687 | // implement it. We used to support it, but Chalk doesn't. Here's the | ||
688 | // correct expect: | ||
689 | // | ||
690 | // 424..609 '{ ...bj2; }': () | ||
691 | // 434..437 'obj': &dyn Baz<i8, i16> | ||
692 | // 459..461 '&S': &S<i8, i16> | ||
693 | // 460..461 'S': S<i8, i16> | ||
694 | // 471..474 'obj': &dyn Bar<usize, i8, i16> | ||
695 | // 496..499 'obj': &dyn Baz<i8, i16> | ||
696 | // 509..512 'obj': &dyn Foo<i8, usize> | ||
697 | // 531..534 'obj': &dyn Bar<usize, i8, i16> | ||
698 | // 544..548 'obj2': &dyn Baz<i8, i16> | ||
699 | // 570..572 '&S': &S<i8, i16> | ||
700 | // 571..572 'S': S<i8, i16> | ||
701 | // 582..583 '_': &dyn Foo<i8, usize> | ||
702 | // 602..606 'obj2': &dyn Baz<i8, i16> | ||
748 | check_infer_with_mismatches( | 703 | check_infer_with_mismatches( |
749 | r#" | 704 | r#" |
750 | #[lang = "sized"] | 705 | //- minicore: coerce_unsized |
751 | pub trait Sized {} | 706 | trait Foo<T, U> {} |
752 | #[lang = "unsize"] | 707 | trait Bar<U, T, X>: Foo<T, U> {} |
753 | pub trait Unsize<T> {} | 708 | trait Baz<T, X>: Bar<usize, T, X> {} |
754 | #[lang = "coerce_unsized"] | 709 | |
755 | pub trait CoerceUnsized<T> {} | 710 | struct S<T, X>; |
756 | 711 | impl<T, X> Foo<T, usize> for S<T, X> {} | |
757 | impl<T: Unsize<U>, U> CoerceUnsized<&U> for &T {} | 712 | impl<T, X> Bar<usize, T, X> for S<T, X> {} |
758 | 713 | impl<T, X> Baz<T, X> for S<T, X> {} | |
759 | trait Foo<T, U> {} | 714 | |
760 | trait Bar<U, T, X>: Foo<T, U> {} | 715 | fn test() { |
761 | trait Baz<T, X>: Bar<usize, T, X> {} | 716 | let obj: &dyn Baz<i8, i16> = &S; |
762 | 717 | let obj: &dyn Bar<_, _, _> = obj; | |
763 | struct S<T, X>; | 718 | let obj: &dyn Foo<_, _> = obj; |
764 | impl<T, X> Foo<T, usize> for S<T, X> {} | 719 | let obj2: &dyn Baz<i8, i16> = &S; |
765 | impl<T, X> Bar<usize, T, X> for S<T, X> {} | 720 | let _: &dyn Foo<_, _> = obj2; |
766 | impl<T, X> Baz<T, X> for S<T, X> {} | 721 | } |
767 | 722 | "#, | |
768 | fn test() { | 723 | expect![[r#" |
769 | let obj: &dyn Baz<i8, i16> = &S; | 724 | 236..421 '{ ...bj2; }': () |
770 | let obj: &dyn Bar<_, _, _> = obj; | 725 | 246..249 'obj': &dyn Baz<i8, i16> |
771 | let obj: &dyn Foo<_, _> = obj; | 726 | 271..273 '&S': &S<i8, i16> |
772 | let obj2: &dyn Baz<i8, i16> = &S; | 727 | 272..273 'S': S<i8, i16> |
773 | let _: &dyn Foo<_, _> = obj2; | 728 | 283..286 'obj': &dyn Bar<{unknown}, {unknown}, {unknown}> |
774 | } | 729 | 308..311 'obj': &dyn Baz<i8, i16> |
775 | "#, | 730 | 321..324 'obj': &dyn Foo<{unknown}, {unknown}> |
776 | expect![[r" | 731 | 343..346 'obj': &dyn Bar<{unknown}, {unknown}, {unknown}> |
777 | 424..609 '{ ...bj2; }': () | 732 | 356..360 'obj2': &dyn Baz<i8, i16> |
778 | 434..437 'obj': &dyn Baz<i8, i16> | 733 | 382..384 '&S': &S<i8, i16> |
779 | 459..461 '&S': &S<i8, i16> | 734 | 383..384 'S': S<i8, i16> |
780 | 460..461 'S': S<i8, i16> | 735 | 394..395 '_': &dyn Foo<{unknown}, {unknown}> |
781 | 471..474 'obj': &dyn Bar<usize, i8, i16> | 736 | 414..418 'obj2': &dyn Baz<i8, i16> |
782 | 496..499 'obj': &dyn Baz<i8, i16> | 737 | 308..311: expected &dyn Bar<{unknown}, {unknown}, {unknown}>, got &dyn Baz<i8, i16> |
783 | 509..512 'obj': &dyn Foo<i8, usize> | 738 | 343..346: expected &dyn Foo<{unknown}, {unknown}>, got &dyn Bar<{unknown}, {unknown}, {unknown}> |
784 | 531..534 'obj': &dyn Bar<usize, i8, i16> | 739 | 414..418: expected &dyn Foo<{unknown}, {unknown}>, got &dyn Baz<i8, i16> |
785 | 544..548 'obj2': &dyn Baz<i8, i16> | 740 | "#]], |
786 | 570..572 '&S': &S<i8, i16> | ||
787 | 571..572 'S': S<i8, i16> | ||
788 | 582..583 '_': &dyn Foo<i8, usize> | ||
789 | 602..606 'obj2': &dyn Baz<i8, i16> | ||
790 | "]], | ||
791 | ); | 741 | ); |
792 | } | 742 | } |
793 | 743 | ||
@@ -795,40 +745,32 @@ fn coerce_unsize_trait_object_to_trait_object() { | |||
795 | fn coerce_unsize_super_trait_cycle() { | 745 | fn coerce_unsize_super_trait_cycle() { |
796 | check_infer_with_mismatches( | 746 | check_infer_with_mismatches( |
797 | r#" | 747 | r#" |
798 | #[lang = "sized"] | 748 | //- minicore: coerce_unsized |
799 | pub trait Sized {} | 749 | trait A {} |
800 | #[lang = "unsize"] | 750 | trait B: C + A {} |
801 | pub trait Unsize<T> {} | 751 | trait C: B {} |
802 | #[lang = "coerce_unsized"] | 752 | trait D: C |
803 | pub trait CoerceUnsized<T> {} | 753 | |
804 | 754 | struct S; | |
805 | impl<T: Unsize<U>, U> CoerceUnsized<&U> for &T {} | 755 | impl A for S {} |
806 | 756 | impl B for S {} | |
807 | trait A {} | 757 | impl C for S {} |
808 | trait B: C + A {} | 758 | impl D for S {} |
809 | trait C: B {} | 759 | |
810 | trait D: C | 760 | fn test() { |
811 | 761 | let obj: &dyn D = &S; | |
812 | struct S; | 762 | let obj: &dyn A = &S; |
813 | impl A for S {} | 763 | } |
814 | impl B for S {} | 764 | "#, |
815 | impl C for S {} | 765 | expect![[r#" |
816 | impl D for S {} | 766 | 140..195 '{ ... &S; }': () |
817 | 767 | 150..153 'obj': &dyn D | |
818 | fn test() { | 768 | 164..166 '&S': &S |
819 | let obj: &dyn D = &S; | 769 | 165..166 'S': S |
820 | let obj: &dyn A = &S; | 770 | 176..179 'obj': &dyn A |
821 | } | 771 | 190..192 '&S': &S |
822 | "#, | 772 | 191..192 'S': S |
823 | expect![[r" | 773 | "#]], |
824 | 328..383 '{ ... &S; }': () | ||
825 | 338..341 'obj': &dyn D | ||
826 | 352..354 '&S': &S | ||
827 | 353..354 'S': S | ||
828 | 364..367 'obj': &dyn A | ||
829 | 378..380 '&S': &S | ||
830 | 379..380 'S': S | ||
831 | "]], | ||
832 | ); | 774 | ); |
833 | } | 775 | } |
834 | 776 | ||
@@ -837,41 +779,35 @@ fn coerce_unsize_generic() { | |||
837 | // FIXME: fix the type mismatches here | 779 | // FIXME: fix the type mismatches here |
838 | check_infer_with_mismatches( | 780 | check_infer_with_mismatches( |
839 | r#" | 781 | r#" |
840 | #[lang = "unsize"] | 782 | //- minicore: coerce_unsized |
841 | pub trait Unsize<T> {} | 783 | struct Foo<T> { t: T }; |
842 | #[lang = "coerce_unsized"] | 784 | struct Bar<T>(Foo<T>); |
843 | pub trait CoerceUnsized<T> {} | ||
844 | |||
845 | impl<T: Unsize<U>, U> CoerceUnsized<&U> for &T {} | ||
846 | 785 | ||
847 | struct Foo<T> { t: T }; | 786 | fn test() { |
848 | struct Bar<T>(Foo<T>); | 787 | let _: &Foo<[usize]> = &Foo { t: [1, 2, 3] }; |
849 | 788 | let _: &Bar<[usize]> = &Bar(Foo { t: [1, 2, 3] }); | |
850 | fn test() { | 789 | } |
851 | let _: &Foo<[usize]> = &Foo { t: [1, 2, 3] }; | 790 | "#, |
852 | let _: &Bar<[usize]> = &Bar(Foo { t: [1, 2, 3] }); | ||
853 | } | ||
854 | "#, | ||
855 | expect![[r#" | 791 | expect![[r#" |
856 | 209..317 '{ ... }); }': () | 792 | 58..166 '{ ... }); }': () |
857 | 219..220 '_': &Foo<[usize]> | 793 | 68..69 '_': &Foo<[usize]> |
858 | 238..259 '&Foo {..., 3] }': &Foo<[usize]> | 794 | 87..108 '&Foo {..., 3] }': &Foo<[usize]> |
859 | 239..259 'Foo { ..., 3] }': Foo<[usize]> | 795 | 88..108 'Foo { ..., 3] }': Foo<[usize]> |
860 | 248..257 '[1, 2, 3]': [usize; 3] | 796 | 97..106 '[1, 2, 3]': [usize; 3] |
861 | 249..250 '1': usize | 797 | 98..99 '1': usize |
862 | 252..253 '2': usize | 798 | 101..102 '2': usize |
863 | 255..256 '3': usize | 799 | 104..105 '3': usize |
864 | 269..270 '_': &Bar<[usize]> | 800 | 118..119 '_': &Bar<[usize]> |
865 | 288..314 '&Bar(F... 3] })': &Bar<[i32; 3]> | 801 | 137..163 '&Bar(F... 3] })': &Bar<[i32; 3]> |
866 | 289..292 'Bar': Bar<[i32; 3]>(Foo<[i32; 3]>) -> Bar<[i32; 3]> | 802 | 138..141 'Bar': Bar<[i32; 3]>(Foo<[i32; 3]>) -> Bar<[i32; 3]> |
867 | 289..314 'Bar(Fo... 3] })': Bar<[i32; 3]> | 803 | 138..163 'Bar(Fo... 3] })': Bar<[i32; 3]> |
868 | 293..313 'Foo { ..., 3] }': Foo<[i32; 3]> | 804 | 142..162 'Foo { ..., 3] }': Foo<[i32; 3]> |
869 | 302..311 '[1, 2, 3]': [i32; 3] | 805 | 151..160 '[1, 2, 3]': [i32; 3] |
870 | 303..304 '1': i32 | 806 | 152..153 '1': i32 |
871 | 306..307 '2': i32 | 807 | 155..156 '2': i32 |
872 | 309..310 '3': i32 | 808 | 158..159 '3': i32 |
873 | 248..257: expected [usize], got [usize; 3] | 809 | 97..106: expected [usize], got [usize; 3] |
874 | 288..314: expected &Bar<[usize]>, got &Bar<[i32; 3]> | 810 | 137..163: expected &Bar<[usize]>, got &Bar<[i32; 3]> |
875 | "#]], | 811 | "#]], |
876 | ); | 812 | ); |
877 | } | 813 | } |
@@ -881,15 +817,7 @@ fn coerce_unsize_apit() { | |||
881 | // FIXME: #8984 | 817 | // FIXME: #8984 |
882 | check_infer_with_mismatches( | 818 | check_infer_with_mismatches( |
883 | r#" | 819 | r#" |
884 | #[lang = "sized"] | 820 | //- minicore: coerce_unsized |
885 | pub trait Sized {} | ||
886 | #[lang = "unsize"] | ||
887 | pub trait Unsize<T> {} | ||
888 | #[lang = "coerce_unsized"] | ||
889 | pub trait CoerceUnsized<T> {} | ||
890 | |||
891 | impl<T: Unsize<U>, U> CoerceUnsized<&U> for &T {} | ||
892 | |||
893 | trait Foo {} | 821 | trait Foo {} |
894 | 822 | ||
895 | fn test(f: impl Foo) { | 823 | fn test(f: impl Foo) { |
@@ -897,12 +825,12 @@ fn test(f: impl Foo) { | |||
897 | } | 825 | } |
898 | "#, | 826 | "#, |
899 | expect![[r#" | 827 | expect![[r#" |
900 | 210..211 'f': impl Foo | 828 | 22..23 'f': impl Foo |
901 | 223..252 '{ ... &f; }': () | 829 | 35..64 '{ ... &f; }': () |
902 | 233..234 '_': &dyn Foo | 830 | 45..46 '_': &dyn Foo |
903 | 247..249 '&f': &impl Foo | 831 | 59..61 '&f': &impl Foo |
904 | 248..249 'f': impl Foo | 832 | 60..61 'f': impl Foo |
905 | 247..249: expected &dyn Foo, got &impl Foo | 833 | 59..61: expected &dyn Foo, got &impl Foo |
906 | "#]], | 834 | "#]], |
907 | ); | 835 | ); |
908 | } | 836 | } |
@@ -998,15 +926,7 @@ fn main() { | |||
998 | fn coerce_unsize_expected_type() { | 926 | fn coerce_unsize_expected_type() { |
999 | check_no_mismatches( | 927 | check_no_mismatches( |
1000 | r#" | 928 | r#" |
1001 | #[lang = "sized"] | 929 | //- minicore: coerce_unsized |
1002 | pub trait Sized {} | ||
1003 | #[lang = "unsize"] | ||
1004 | pub trait Unsize<T> {} | ||
1005 | #[lang = "coerce_unsized"] | ||
1006 | pub trait CoerceUnsized<T> {} | ||
1007 | |||
1008 | impl<T: Unsize<U>, U> CoerceUnsized<&U> for &T {} | ||
1009 | |||
1010 | fn main() { | 930 | fn main() { |
1011 | let foo: &[u32] = &[1, 2]; | 931 | let foo: &[u32] = &[1, 2]; |
1012 | let foo: &[u32] = match true { | 932 | let foo: &[u32] = match true { |
diff --git a/crates/hir_ty/src/tests/method_resolution.rs b/crates/hir_ty/src/tests/method_resolution.rs index f26b2c8a7..d9b5ee9cf 100644 --- a/crates/hir_ty/src/tests/method_resolution.rs +++ b/crates/hir_ty/src/tests/method_resolution.rs | |||
@@ -780,10 +780,7 @@ fn test() { (&S).foo(); } | |||
780 | fn method_resolution_unsize_array() { | 780 | fn method_resolution_unsize_array() { |
781 | check_types( | 781 | check_types( |
782 | r#" | 782 | r#" |
783 | #[lang = "slice"] | 783 | //- minicore: slice |
784 | impl<T> [T] { | ||
785 | fn len(&self) -> usize { loop {} } | ||
786 | } | ||
787 | fn test() { | 784 | fn test() { |
788 | let a = [1, 2, 3]; | 785 | let a = [1, 2, 3]; |
789 | a.len(); | 786 | a.len(); |
@@ -1178,11 +1175,7 @@ fn main() { | |||
1178 | fn autoderef_visibility_field() { | 1175 | fn autoderef_visibility_field() { |
1179 | check_infer( | 1176 | check_infer( |
1180 | r#" | 1177 | r#" |
1181 | #[lang = "deref"] | 1178 | //- minicore: deref |
1182 | pub trait Deref { | ||
1183 | type Target; | ||
1184 | fn deref(&self) -> &Self::Target; | ||
1185 | } | ||
1186 | mod a { | 1179 | mod a { |
1187 | pub struct Foo(pub char); | 1180 | pub struct Foo(pub char); |
1188 | pub struct Bar(i32); | 1181 | pub struct Bar(i32); |
@@ -1191,7 +1184,7 @@ mod a { | |||
1191 | Self(0) | 1184 | Self(0) |
1192 | } | 1185 | } |
1193 | } | 1186 | } |
1194 | impl super::Deref for Bar { | 1187 | impl core::ops::Deref for Bar { |
1195 | type Target = Foo; | 1188 | type Target = Foo; |
1196 | fn deref(&self) -> &Foo { | 1189 | fn deref(&self) -> &Foo { |
1197 | &Foo('z') | 1190 | &Foo('z') |
@@ -1205,22 +1198,21 @@ mod b { | |||
1205 | } | 1198 | } |
1206 | "#, | 1199 | "#, |
1207 | expect![[r#" | 1200 | expect![[r#" |
1208 | 67..71 'self': &Self | 1201 | 107..138 '{ ... }': Bar |
1209 | 200..231 '{ ... }': Bar | 1202 | 121..125 'Self': Bar(i32) -> Bar |
1210 | 214..218 'Self': Bar(i32) -> Bar | 1203 | 121..128 'Self(0)': Bar |
1211 | 214..221 'Self(0)': Bar | 1204 | 126..127 '0': i32 |
1212 | 219..220 '0': i32 | 1205 | 226..230 'self': &Bar |
1213 | 315..319 'self': &Bar | 1206 | 240..273 '{ ... }': &Foo |
1214 | 329..362 '{ ... }': &Foo | 1207 | 254..263 '&Foo('z')': &Foo |
1215 | 343..352 '&Foo('z')': &Foo | 1208 | 255..258 'Foo': Foo(char) -> Foo |
1216 | 344..347 'Foo': Foo(char) -> Foo | 1209 | 255..263 'Foo('z')': Foo |
1217 | 344..352 'Foo('z')': Foo | 1210 | 259..262 ''z'': char |
1218 | 348..351 ''z'': char | 1211 | 303..350 '{ ... }': () |
1219 | 392..439 '{ ... }': () | 1212 | 317..318 'x': char |
1220 | 406..407 'x': char | 1213 | 321..339 'super:...r::new': fn new() -> Bar |
1221 | 410..428 'super:...r::new': fn new() -> Bar | 1214 | 321..341 'super:...:new()': Bar |
1222 | 410..430 'super:...:new()': Bar | 1215 | 321..343 'super:...ew().0': char |
1223 | 410..432 'super:...ew().0': char | ||
1224 | "#]], | 1216 | "#]], |
1225 | ) | 1217 | ) |
1226 | } | 1218 | } |
@@ -1230,11 +1222,7 @@ fn autoderef_visibility_method() { | |||
1230 | cov_mark::check!(autoderef_candidate_not_visible); | 1222 | cov_mark::check!(autoderef_candidate_not_visible); |
1231 | check_infer( | 1223 | check_infer( |
1232 | r#" | 1224 | r#" |
1233 | #[lang = "deref"] | 1225 | //- minicore: deref |
1234 | pub trait Deref { | ||
1235 | type Target; | ||
1236 | fn deref(&self) -> &Self::Target; | ||
1237 | } | ||
1238 | mod a { | 1226 | mod a { |
1239 | pub struct Foo(pub char); | 1227 | pub struct Foo(pub char); |
1240 | impl Foo { | 1228 | impl Foo { |
@@ -1251,7 +1239,7 @@ mod a { | |||
1251 | self.0 | 1239 | self.0 |
1252 | } | 1240 | } |
1253 | } | 1241 | } |
1254 | impl super::Deref for Bar { | 1242 | impl core::ops::Deref for Bar { |
1255 | type Target = Foo; | 1243 | type Target = Foo; |
1256 | fn deref(&self) -> &Foo { | 1244 | fn deref(&self) -> &Foo { |
1257 | &Foo('z') | 1245 | &Foo('z') |
@@ -1265,30 +1253,29 @@ mod b { | |||
1265 | } | 1253 | } |
1266 | "#, | 1254 | "#, |
1267 | expect![[r#" | 1255 | expect![[r#" |
1268 | 67..71 'self': &Self | 1256 | 75..79 'self': &Foo |
1269 | 168..172 'self': &Foo | 1257 | 89..119 '{ ... }': char |
1270 | 182..212 '{ ... }': char | 1258 | 103..107 'self': &Foo |
1271 | 196..200 'self': &Foo | 1259 | 103..109 'self.0': char |
1272 | 196..202 'self.0': char | 1260 | 195..226 '{ ... }': Bar |
1273 | 288..319 '{ ... }': Bar | 1261 | 209..213 'Self': Bar(i32) -> Bar |
1274 | 302..306 'Self': Bar(i32) -> Bar | 1262 | 209..216 'Self(0)': Bar |
1275 | 302..309 'Self(0)': Bar | 1263 | 214..215 '0': i32 |
1276 | 307..308 '0': i32 | 1264 | 245..249 'self': &Bar |
1277 | 338..342 'self': &Bar | 1265 | 258..288 '{ ... }': i32 |
1278 | 351..381 '{ ... }': i32 | 1266 | 272..276 'self': &Bar |
1279 | 365..369 'self': &Bar | 1267 | 272..278 'self.0': i32 |
1280 | 365..371 'self.0': i32 | 1268 | 376..380 'self': &Bar |
1281 | 465..469 'self': &Bar | 1269 | 390..423 '{ ... }': &Foo |
1282 | 479..512 '{ ... }': &Foo | 1270 | 404..413 '&Foo('z')': &Foo |
1283 | 493..502 '&Foo('z')': &Foo | 1271 | 405..408 'Foo': Foo(char) -> Foo |
1284 | 494..497 'Foo': Foo(char) -> Foo | 1272 | 405..413 'Foo('z')': Foo |
1285 | 494..502 'Foo('z')': Foo | 1273 | 409..412 ''z'': char |
1286 | 498..501 ''z'': char | 1274 | 453..506 '{ ... }': () |
1287 | 542..595 '{ ... }': () | 1275 | 467..468 'x': char |
1288 | 556..557 'x': char | 1276 | 471..489 'super:...r::new': fn new() -> Bar |
1289 | 560..578 'super:...r::new': fn new() -> Bar | 1277 | 471..491 'super:...:new()': Bar |
1290 | 560..580 'super:...:new()': Bar | 1278 | 471..499 'super:...ango()': char |
1291 | 560..588 'super:...ango()': char | ||
1292 | "#]], | 1279 | "#]], |
1293 | ) | 1280 | ) |
1294 | } | 1281 | } |
diff --git a/crates/hir_ty/src/tests/regression.rs b/crates/hir_ty/src/tests/regression.rs index 1019e783b..abd9c385a 100644 --- a/crates/hir_ty/src/tests/regression.rs +++ b/crates/hir_ty/src/tests/regression.rs | |||
@@ -927,35 +927,33 @@ fn issue_6628() { | |||
927 | fn issue_6852() { | 927 | fn issue_6852() { |
928 | check_infer( | 928 | check_infer( |
929 | r#" | 929 | r#" |
930 | #[lang = "deref"] | 930 | //- minicore: deref |
931 | pub trait Deref { | 931 | use core::ops::Deref; |
932 | type Target; | ||
933 | } | ||
934 | 932 | ||
935 | struct BufWriter {} | 933 | struct BufWriter {} |
936 | 934 | ||
937 | struct Mutex<T> {} | 935 | struct Mutex<T> {} |
938 | struct MutexGuard<'a, T> {} | 936 | struct MutexGuard<'a, T> {} |
939 | impl<T> Mutex<T> { | 937 | impl<T> Mutex<T> { |
940 | fn lock(&self) -> MutexGuard<'_, T> {} | 938 | fn lock(&self) -> MutexGuard<'_, T> {} |
941 | } | 939 | } |
942 | impl<'a, T: 'a> Deref for MutexGuard<'a, T> { | 940 | impl<'a, T: 'a> Deref for MutexGuard<'a, T> { |
943 | type Target = T; | 941 | type Target = T; |
944 | } | 942 | } |
945 | fn flush(&self) { | 943 | fn flush(&self) { |
946 | let w: &Mutex<BufWriter>; | 944 | let w: &Mutex<BufWriter>; |
947 | *(w.lock()); | 945 | *(w.lock()); |
948 | } | 946 | } |
949 | "#, | 947 | "#, |
950 | expect![[r#" | 948 | expect![[r#" |
951 | 156..160 'self': &Mutex<T> | 949 | 123..127 'self': &Mutex<T> |
952 | 183..185 '{}': () | 950 | 150..152 '{}': () |
953 | 267..271 'self': &{unknown} | 951 | 234..238 'self': &{unknown} |
954 | 273..323 '{ ...()); }': () | 952 | 240..290 '{ ...()); }': () |
955 | 283..284 'w': &Mutex<BufWriter> | 953 | 250..251 'w': &Mutex<BufWriter> |
956 | 309..320 '*(w.lock())': BufWriter | 954 | 276..287 '*(w.lock())': BufWriter |
957 | 311..312 'w': &Mutex<BufWriter> | 955 | 278..279 'w': &Mutex<BufWriter> |
958 | 311..319 'w.lock()': MutexGuard<BufWriter> | 956 | 278..286 'w.lock()': MutexGuard<BufWriter> |
959 | "#]], | 957 | "#]], |
960 | ); | 958 | ); |
961 | } | 959 | } |
@@ -977,37 +975,33 @@ fn param_overrides_fn() { | |||
977 | fn lifetime_from_chalk_during_deref() { | 975 | fn lifetime_from_chalk_during_deref() { |
978 | check_types( | 976 | check_types( |
979 | r#" | 977 | r#" |
980 | #[lang = "deref"] | 978 | //- minicore: deref |
981 | pub trait Deref { | 979 | struct Box<T: ?Sized> {} |
982 | type Target; | 980 | impl<T> core::ops::Deref for Box<T> { |
983 | } | 981 | type Target = T; |
984 | |||
985 | struct Box<T: ?Sized> {} | ||
986 | impl<T> Deref for Box<T> { | ||
987 | type Target = T; | ||
988 | 982 | ||
989 | fn deref(&self) -> &Self::Target { | 983 | fn deref(&self) -> &Self::Target { |
990 | loop {} | 984 | loop {} |
991 | } | 985 | } |
992 | } | 986 | } |
993 | 987 | ||
994 | trait Iterator { | 988 | trait Iterator { |
995 | type Item; | 989 | type Item; |
996 | } | 990 | } |
997 | 991 | ||
998 | pub struct Iter<'a, T: 'a> { | 992 | pub struct Iter<'a, T: 'a> { |
999 | inner: Box<dyn IterTrait<'a, T, Item = &'a T> + 'a>, | 993 | inner: Box<dyn IterTrait<'a, T, Item = &'a T> + 'a>, |
1000 | } | 994 | } |
1001 | 995 | ||
1002 | trait IterTrait<'a, T: 'a>: Iterator<Item = &'a T> { | 996 | trait IterTrait<'a, T: 'a>: Iterator<Item = &'a T> { |
1003 | fn clone_box(&self); | 997 | fn clone_box(&self); |
1004 | } | 998 | } |
1005 | 999 | ||
1006 | fn clone_iter<T>(s: Iter<T>) { | 1000 | fn clone_iter<T>(s: Iter<T>) { |
1007 | s.inner.clone_box(); | 1001 | s.inner.clone_box(); |
1008 | //^^^^^^^^^^^^^^^^^^^ () | 1002 | //^^^^^^^^^^^^^^^^^^^ () |
1009 | } | 1003 | } |
1010 | "#, | 1004 | "#, |
1011 | ) | 1005 | ) |
1012 | } | 1006 | } |
1013 | 1007 | ||
diff --git a/crates/hir_ty/src/tests/simple.rs b/crates/hir_ty/src/tests/simple.rs index 3418ed21e..68776f3c0 100644 --- a/crates/hir_ty/src/tests/simple.rs +++ b/crates/hir_ty/src/tests/simple.rs | |||
@@ -113,7 +113,7 @@ fn type_alias_in_struct_lit() { | |||
113 | fn infer_ranges() { | 113 | fn infer_ranges() { |
114 | check_types( | 114 | check_types( |
115 | r#" | 115 | r#" |
116 | //- /main.rs crate:main deps:core | 116 | //- minicore: range |
117 | fn test() { | 117 | fn test() { |
118 | let a = ..; | 118 | let a = ..; |
119 | let b = 1..; | 119 | let b = 1..; |
@@ -125,32 +125,6 @@ fn test() { | |||
125 | let t = (a, b, c, d, e, f); | 125 | let t = (a, b, c, d, e, f); |
126 | t; | 126 | t; |
127 | } //^ (RangeFull, RangeFrom<i32>, RangeTo<u32>, Range<usize>, RangeToInclusive<i32>, RangeInclusive<char>) | 127 | } //^ (RangeFull, RangeFrom<i32>, RangeTo<u32>, Range<usize>, RangeToInclusive<i32>, RangeInclusive<char>) |
128 | |||
129 | //- /core.rs crate:core | ||
130 | #[prelude_import] use prelude::*; | ||
131 | mod prelude {} | ||
132 | |||
133 | pub mod ops { | ||
134 | pub struct Range<Idx> { | ||
135 | pub start: Idx, | ||
136 | pub end: Idx, | ||
137 | } | ||
138 | pub struct RangeFrom<Idx> { | ||
139 | pub start: Idx, | ||
140 | } | ||
141 | struct RangeFull; | ||
142 | pub struct RangeInclusive<Idx> { | ||
143 | start: Idx, | ||
144 | end: Idx, | ||
145 | is_empty: u8, | ||
146 | } | ||
147 | pub struct RangeTo<Idx> { | ||
148 | pub end: Idx, | ||
149 | } | ||
150 | pub struct RangeToInclusive<Idx> { | ||
151 | pub end: Idx, | ||
152 | } | ||
153 | } | ||
154 | "#, | 128 | "#, |
155 | ); | 129 | ); |
156 | } | 130 | } |
@@ -175,16 +149,17 @@ fn test() { | |||
175 | fn infer_basics() { | 149 | fn infer_basics() { |
176 | check_infer( | 150 | check_infer( |
177 | r#" | 151 | r#" |
178 | fn test(a: u32, b: isize, c: !, d: &str) { | 152 | fn test(a: u32, b: isize, c: !, d: &str) { |
179 | a; | 153 | a; |
180 | b; | 154 | b; |
181 | c; | 155 | c; |
182 | d; | 156 | d; |
183 | 1usize; | 157 | 1usize; |
184 | 1isize; | 158 | 1isize; |
185 | "test"; | 159 | "test"; |
186 | 1.0f32; | 160 | 1.0f32; |
187 | }"#, | 161 | } |
162 | "#, | ||
188 | expect![[r#" | 163 | expect![[r#" |
189 | 8..9 'a': u32 | 164 | 8..9 'a': u32 |
190 | 16..17 'b': isize | 165 | 16..17 'b': isize |
@@ -207,15 +182,15 @@ fn infer_basics() { | |||
207 | fn infer_let() { | 182 | fn infer_let() { |
208 | check_infer( | 183 | check_infer( |
209 | r#" | 184 | r#" |
210 | fn test() { | 185 | fn test() { |
211 | let a = 1isize; | 186 | let a = 1isize; |
212 | let b: usize = 1; | 187 | let b: usize = 1; |
213 | let c = b; | 188 | let c = b; |
214 | let d: u32; | 189 | let d: u32; |
215 | let e; | 190 | let e; |
216 | let f: i32 = e; | 191 | let f: i32 = e; |
217 | } | 192 | } |
218 | "#, | 193 | "#, |
219 | expect![[r#" | 194 | expect![[r#" |
220 | 10..117 '{ ...= e; }': () | 195 | 10..117 '{ ...= e; }': () |
221 | 20..21 'a': isize | 196 | 20..21 'a': isize |
@@ -236,17 +211,17 @@ fn infer_let() { | |||
236 | fn infer_paths() { | 211 | fn infer_paths() { |
237 | check_infer( | 212 | check_infer( |
238 | r#" | 213 | r#" |
239 | fn a() -> u32 { 1 } | 214 | fn a() -> u32 { 1 } |
240 | 215 | ||
241 | mod b { | 216 | mod b { |
242 | fn c() -> u32 { 1 } | 217 | fn c() -> u32 { 1 } |
243 | } | 218 | } |
244 | 219 | ||
245 | fn test() { | 220 | fn test() { |
246 | a(); | 221 | a(); |
247 | b::c(); | 222 | b::c(); |
248 | } | 223 | } |
249 | "#, | 224 | "#, |
250 | expect![[r#" | 225 | expect![[r#" |
251 | 14..19 '{ 1 }': u32 | 226 | 14..19 '{ 1 }': u32 |
252 | 16..17 '1': u32 | 227 | 16..17 '1': u32 |
@@ -265,17 +240,17 @@ fn infer_paths() { | |||
265 | fn infer_path_type() { | 240 | fn infer_path_type() { |
266 | check_infer( | 241 | check_infer( |
267 | r#" | 242 | r#" |
268 | struct S; | 243 | struct S; |
269 | 244 | ||
270 | impl S { | 245 | impl S { |
271 | fn foo() -> i32 { 1 } | 246 | fn foo() -> i32 { 1 } |
272 | } | 247 | } |
273 | 248 | ||
274 | fn test() { | 249 | fn test() { |
275 | S::foo(); | 250 | S::foo(); |
276 | <S>::foo(); | 251 | <S>::foo(); |
277 | } | 252 | } |
278 | "#, | 253 | "#, |
279 | expect![[r#" | 254 | expect![[r#" |
280 | 40..45 '{ 1 }': i32 | 255 | 40..45 '{ 1 }': i32 |
281 | 42..43 '1': i32 | 256 | 42..43 '1': i32 |
@@ -292,21 +267,21 @@ fn infer_path_type() { | |||
292 | fn infer_struct() { | 267 | fn infer_struct() { |
293 | check_infer( | 268 | check_infer( |
294 | r#" | 269 | r#" |
295 | struct A { | 270 | struct A { |
296 | b: B, | 271 | b: B, |
297 | c: C, | 272 | c: C, |
298 | } | 273 | } |
299 | struct B; | 274 | struct B; |
300 | struct C(usize); | 275 | struct C(usize); |
301 | 276 | ||
302 | fn test() { | 277 | fn test() { |
303 | let c = C(1); | 278 | let c = C(1); |
304 | B; | 279 | B; |
305 | let a: A = A { b: B, c: C(1) }; | 280 | let a: A = A { b: B, c: C(1) }; |
306 | a.b; | 281 | a.b; |
307 | a.c; | 282 | a.c; |
308 | } | 283 | } |
309 | "#, | 284 | "#, |
310 | expect![[r#" | 285 | expect![[r#" |
311 | 71..153 '{ ...a.c; }': () | 286 | 71..153 '{ ...a.c; }': () |
312 | 81..82 'c': C | 287 | 81..82 'c': C |
@@ -332,14 +307,15 @@ fn infer_struct() { | |||
332 | fn infer_enum() { | 307 | fn infer_enum() { |
333 | check_infer( | 308 | check_infer( |
334 | r#" | 309 | r#" |
335 | enum E { | 310 | enum E { |
336 | V1 { field: u32 }, | 311 | V1 { field: u32 }, |
337 | V2 | 312 | V2 |
338 | } | 313 | } |
339 | fn test() { | 314 | fn test() { |
340 | E::V1 { field: 1 }; | 315 | E::V1 { field: 1 }; |
341 | E::V2; | 316 | E::V2; |
342 | }"#, | 317 | } |
318 | "#, | ||
343 | expect![[r#" | 319 | expect![[r#" |
344 | 51..89 '{ ...:V2; }': () | 320 | 51..89 '{ ...:V2; }': () |
345 | 57..75 'E::V1 ...d: 1 }': E | 321 | 57..75 'E::V1 ...d: 1 }': E |
@@ -353,23 +329,23 @@ fn infer_enum() { | |||
353 | fn infer_union() { | 329 | fn infer_union() { |
354 | check_infer( | 330 | check_infer( |
355 | r#" | 331 | r#" |
356 | union MyUnion { | 332 | union MyUnion { |
357 | foo: u32, | 333 | foo: u32, |
358 | bar: f32, | 334 | bar: f32, |
359 | } | 335 | } |
360 | 336 | ||
361 | fn test() { | 337 | fn test() { |
362 | let u = MyUnion { foo: 0 }; | 338 | let u = MyUnion { foo: 0 }; |
363 | unsafe { baz(u); } | 339 | unsafe { baz(u); } |
364 | let u = MyUnion { bar: 0.0 }; | 340 | let u = MyUnion { bar: 0.0 }; |
365 | unsafe { baz(u); } | 341 | unsafe { baz(u); } |
366 | } | 342 | } |
367 | 343 | ||
368 | unsafe fn baz(u: MyUnion) { | 344 | unsafe fn baz(u: MyUnion) { |
369 | let inner = u.foo; | 345 | let inner = u.foo; |
370 | let inner = u.bar; | 346 | let inner = u.bar; |
371 | } | 347 | } |
372 | "#, | 348 | "#, |
373 | expect![[r#" | 349 | expect![[r#" |
374 | 57..172 '{ ...); } }': () | 350 | 57..172 '{ ...); } }': () |
375 | 67..68 'u': MyUnion | 351 | 67..68 'u': MyUnion |
@@ -404,19 +380,19 @@ fn infer_union() { | |||
404 | fn infer_refs() { | 380 | fn infer_refs() { |
405 | check_infer( | 381 | check_infer( |
406 | r#" | 382 | r#" |
407 | fn test(a: &u32, b: &mut u32, c: *const u32, d: *mut u32) { | 383 | fn test(a: &u32, b: &mut u32, c: *const u32, d: *mut u32) { |
408 | a; | 384 | a; |
409 | *a; | 385 | *a; |
410 | &a; | 386 | &a; |
411 | &mut a; | 387 | &mut a; |
412 | b; | 388 | b; |
413 | *b; | 389 | *b; |
414 | &b; | 390 | &b; |
415 | c; | 391 | c; |
416 | *c; | 392 | *c; |
417 | d; | 393 | d; |
418 | *d; | 394 | *d; |
419 | } | 395 | } |
420 | "#, | 396 | "#, |
421 | expect![[r#" | 397 | expect![[r#" |
422 | 8..9 'a': &u32 | 398 | 8..9 'a': &u32 |
@@ -450,11 +426,11 @@ fn infer_refs() { | |||
450 | fn infer_raw_ref() { | 426 | fn infer_raw_ref() { |
451 | check_infer( | 427 | check_infer( |
452 | r#" | 428 | r#" |
453 | fn test(a: i32) { | 429 | fn test(a: i32) { |
454 | &raw mut a; | 430 | &raw mut a; |
455 | &raw const a; | 431 | &raw const a; |
456 | } | 432 | } |
457 | "#, | 433 | "#, |
458 | expect![[r#" | 434 | expect![[r#" |
459 | 8..9 'a': i32 | 435 | 8..9 'a': i32 |
460 | 16..53 '{ ...t a; }': () | 436 | 16..53 '{ ...t a; }': () |
@@ -524,26 +500,26 @@ h"; | |||
524 | fn infer_unary_op() { | 500 | fn infer_unary_op() { |
525 | check_infer( | 501 | check_infer( |
526 | r#" | 502 | r#" |
527 | enum SomeType {} | 503 | enum SomeType {} |
528 | 504 | ||
529 | fn test(x: SomeType) { | 505 | fn test(x: SomeType) { |
530 | let b = false; | 506 | let b = false; |
531 | let c = !b; | 507 | let c = !b; |
532 | let a = 100; | 508 | let a = 100; |
533 | let d: i128 = -a; | 509 | let d: i128 = -a; |
534 | let e = -100; | 510 | let e = -100; |
535 | let f = !!!true; | 511 | let f = !!!true; |
536 | let g = !42; | 512 | let g = !42; |
537 | let h = !10u32; | 513 | let h = !10u32; |
538 | let j = !a; | 514 | let j = !a; |
539 | -3.14; | 515 | -3.14; |
540 | !3; | 516 | !3; |
541 | -x; | 517 | -x; |
542 | !x; | 518 | !x; |
543 | -"hello"; | 519 | -"hello"; |
544 | !"hello"; | 520 | !"hello"; |
545 | } | 521 | } |
546 | "#, | 522 | "#, |
547 | expect![[r#" | 523 | expect![[r#" |
548 | 26..27 'x': SomeType | 524 | 26..27 'x': SomeType |
549 | 39..271 '{ ...lo"; }': () | 525 | 39..271 '{ ...lo"; }': () |
@@ -594,19 +570,19 @@ fn infer_unary_op() { | |||
594 | fn infer_backwards() { | 570 | fn infer_backwards() { |
595 | check_infer( | 571 | check_infer( |
596 | r#" | 572 | r#" |
597 | fn takes_u32(x: u32) {} | 573 | fn takes_u32(x: u32) {} |
598 | 574 | ||
599 | struct S { i32_field: i32 } | 575 | struct S { i32_field: i32 } |
600 | 576 | ||
601 | fn test() -> &mut &f64 { | 577 | fn test() -> &mut &f64 { |
602 | let a = unknown_function(); | 578 | let a = unknown_function(); |
603 | takes_u32(a); | 579 | takes_u32(a); |
604 | let b = unknown_function(); | 580 | let b = unknown_function(); |
605 | S { i32_field: b }; | 581 | S { i32_field: b }; |
606 | let c = unknown_function(); | 582 | let c = unknown_function(); |
607 | &mut &c | 583 | &mut &c |
608 | } | 584 | } |
609 | "#, | 585 | "#, |
610 | expect![[r#" | 586 | expect![[r#" |
611 | 13..14 'x': u32 | 587 | 13..14 'x': u32 |
612 | 21..23 '{}': () | 588 | 21..23 '{}': () |
@@ -636,23 +612,23 @@ fn infer_backwards() { | |||
636 | fn infer_self() { | 612 | fn infer_self() { |
637 | check_infer( | 613 | check_infer( |
638 | r#" | 614 | r#" |
639 | struct S; | 615 | struct S; |
640 | 616 | ||
641 | impl S { | 617 | impl S { |
642 | fn test(&self) { | 618 | fn test(&self) { |
643 | self; | 619 | self; |
644 | } | 620 | } |
645 | fn test2(self: &Self) { | 621 | fn test2(self: &Self) { |
646 | self; | 622 | self; |
647 | } | 623 | } |
648 | fn test3() -> Self { | 624 | fn test3() -> Self { |
649 | S {} | 625 | S {} |
650 | } | 626 | } |
651 | fn test4() -> Self { | 627 | fn test4() -> Self { |
652 | Self {} | 628 | Self {} |
653 | } | 629 | } |
654 | } | 630 | } |
655 | "#, | 631 | "#, |
656 | expect![[r#" | 632 | expect![[r#" |
657 | 33..37 'self': &S | 633 | 33..37 'self': &S |
658 | 39..60 '{ ... }': () | 634 | 39..60 '{ ... }': () |
@@ -672,30 +648,30 @@ fn infer_self() { | |||
672 | fn infer_self_as_path() { | 648 | fn infer_self_as_path() { |
673 | check_infer( | 649 | check_infer( |
674 | r#" | 650 | r#" |
675 | struct S1; | 651 | struct S1; |
676 | struct S2(isize); | 652 | struct S2(isize); |
677 | enum E { | 653 | enum E { |
678 | V1, | 654 | V1, |
679 | V2(u32), | 655 | V2(u32), |
680 | } | 656 | } |
681 | 657 | ||
682 | impl S1 { | 658 | impl S1 { |
683 | fn test() { | 659 | fn test() { |
684 | Self; | 660 | Self; |
685 | } | 661 | } |
686 | } | 662 | } |
687 | impl S2 { | 663 | impl S2 { |
688 | fn test() { | 664 | fn test() { |
689 | Self(1); | 665 | Self(1); |
690 | } | 666 | } |
691 | } | 667 | } |
692 | impl E { | 668 | impl E { |
693 | fn test() { | 669 | fn test() { |
694 | Self::V1; | 670 | Self::V1; |
695 | Self::V2(1); | 671 | Self::V2(1); |
696 | } | 672 | } |
697 | } | 673 | } |
698 | "#, | 674 | "#, |
699 | expect![[r#" | 675 | expect![[r#" |
700 | 86..107 '{ ... }': () | 676 | 86..107 '{ ... }': () |
701 | 96..100 'Self': S1 | 677 | 96..100 'Self': S1 |
@@ -716,26 +692,26 @@ fn infer_self_as_path() { | |||
716 | fn infer_binary_op() { | 692 | fn infer_binary_op() { |
717 | check_infer( | 693 | check_infer( |
718 | r#" | 694 | r#" |
719 | fn f(x: bool) -> i32 { | 695 | fn f(x: bool) -> i32 { |
720 | 0i32 | 696 | 0i32 |
721 | } | 697 | } |
722 | 698 | ||
723 | fn test() -> bool { | 699 | fn test() -> bool { |
724 | let x = a && b; | 700 | let x = a && b; |
725 | let y = true || false; | 701 | let y = true || false; |
726 | let z = x == y; | 702 | let z = x == y; |
727 | let t = x != y; | 703 | let t = x != y; |
728 | let minus_forty: isize = -40isize; | 704 | let minus_forty: isize = -40isize; |
729 | let h = minus_forty <= CONST_2; | 705 | let h = minus_forty <= CONST_2; |
730 | let c = f(z || y) + 5; | 706 | let c = f(z || y) + 5; |
731 | let d = b; | 707 | let d = b; |
732 | let g = minus_forty ^= i; | 708 | let g = minus_forty ^= i; |
733 | let ten: usize = 10; | 709 | let ten: usize = 10; |
734 | let ten_is_eleven = ten == some_num; | 710 | let ten_is_eleven = ten == some_num; |
735 | 711 | ||
736 | ten < 3 | 712 | ten < 3 |
737 | } | 713 | } |
738 | "#, | 714 | "#, |
739 | expect![[r#" | 715 | expect![[r#" |
740 | 5..6 'x': bool | 716 | 5..6 'x': bool |
741 | 21..33 '{ 0i32 }': i32 | 717 | 21..33 '{ 0i32 }': i32 |
@@ -795,11 +771,11 @@ fn infer_binary_op() { | |||
795 | fn infer_shift_op() { | 771 | fn infer_shift_op() { |
796 | check_infer( | 772 | check_infer( |
797 | r#" | 773 | r#" |
798 | fn test() { | 774 | fn test() { |
799 | 1u32 << 5u8; | 775 | 1u32 << 5u8; |
800 | 1u32 >> 5u8; | 776 | 1u32 >> 5u8; |
801 | } | 777 | } |
802 | "#, | 778 | "#, |
803 | expect![[r#" | 779 | expect![[r#" |
804 | 10..47 '{ ...5u8; }': () | 780 | 10..47 '{ ...5u8; }': () |
805 | 16..20 '1u32': u32 | 781 | 16..20 '1u32': u32 |
@@ -816,29 +792,29 @@ fn infer_shift_op() { | |||
816 | fn infer_field_autoderef() { | 792 | fn infer_field_autoderef() { |
817 | check_infer( | 793 | check_infer( |
818 | r#" | 794 | r#" |
819 | struct A { | 795 | struct A { |
820 | b: B, | 796 | b: B, |
821 | } | 797 | } |
822 | struct B; | 798 | struct B; |
823 | |||
824 | fn test1(a: A) { | ||
825 | let a1 = a; | ||
826 | a1.b; | ||
827 | let a2 = &a; | ||
828 | a2.b; | ||
829 | let a3 = &mut a; | ||
830 | a3.b; | ||
831 | let a4 = &&&&&&&a; | ||
832 | a4.b; | ||
833 | let a5 = &mut &&mut &&mut a; | ||
834 | a5.b; | ||
835 | } | ||
836 | 799 | ||
837 | fn test2(a1: *const A, a2: *mut A) { | 800 | fn test1(a: A) { |
838 | a1.b; | 801 | let a1 = a; |
839 | a2.b; | 802 | a1.b; |
840 | } | 803 | let a2 = &a; |
841 | "#, | 804 | a2.b; |
805 | let a3 = &mut a; | ||
806 | a3.b; | ||
807 | let a4 = &&&&&&&a; | ||
808 | a4.b; | ||
809 | let a5 = &mut &&mut &&mut a; | ||
810 | a5.b; | ||
811 | } | ||
812 | |||
813 | fn test2(a1: *const A, a2: *mut A) { | ||
814 | a1.b; | ||
815 | a2.b; | ||
816 | } | ||
817 | "#, | ||
842 | expect![[r#" | 818 | expect![[r#" |
843 | 43..44 'a': A | 819 | 43..44 'a': A |
844 | 49..212 '{ ...5.b; }': () | 820 | 49..212 '{ ...5.b; }': () |
@@ -891,58 +867,53 @@ fn infer_field_autoderef() { | |||
891 | fn infer_argument_autoderef() { | 867 | fn infer_argument_autoderef() { |
892 | check_infer( | 868 | check_infer( |
893 | r#" | 869 | r#" |
894 | #[lang = "deref"] | 870 | //- minicore: deref |
895 | pub trait Deref { | 871 | use core::ops::Deref; |
896 | type Target; | 872 | struct A<T>(T); |
897 | fn deref(&self) -> &Self::Target; | ||
898 | } | ||
899 | |||
900 | struct A<T>(T); | ||
901 | 873 | ||
902 | impl<T> A<T> { | 874 | impl<T> A<T> { |
903 | fn foo(&self) -> &T { | 875 | fn foo(&self) -> &T { |
904 | &self.0 | 876 | &self.0 |
905 | } | 877 | } |
906 | } | 878 | } |
907 | 879 | ||
908 | struct B<T>(T); | 880 | struct B<T>(T); |
909 | 881 | ||
910 | impl<T> Deref for B<T> { | 882 | impl<T> Deref for B<T> { |
911 | type Target = T; | 883 | type Target = T; |
912 | fn deref(&self) -> &Self::Target { | 884 | fn deref(&self) -> &Self::Target { |
913 | &self.0 | 885 | &self.0 |
914 | } | 886 | } |
915 | } | 887 | } |
916 | 888 | ||
917 | fn test() { | 889 | fn test() { |
918 | let t = A::foo(&&B(B(A(42)))); | 890 | let t = A::foo(&&B(B(A(42)))); |
919 | } | 891 | } |
920 | "#, | 892 | "#, |
921 | expect![[r#" | 893 | expect![[r#" |
922 | 67..71 'self': &Self | 894 | 66..70 'self': &A<T> |
923 | 138..142 'self': &A<T> | 895 | 78..101 '{ ... }': &T |
924 | 150..173 '{ ... }': &T | 896 | 88..95 '&self.0': &T |
925 | 160..167 '&self.0': &T | 897 | 89..93 'self': &A<T> |
926 | 161..165 'self': &A<T> | 898 | 89..95 'self.0': T |
927 | 161..167 'self.0': T | 899 | 182..186 'self': &B<T> |
928 | 254..258 'self': &B<T> | 900 | 205..228 '{ ... }': &T |
929 | 277..300 '{ ... }': &T | 901 | 215..222 '&self.0': &T |
930 | 287..294 '&self.0': &T | 902 | 216..220 'self': &B<T> |
931 | 288..292 'self': &B<T> | 903 | 216..222 'self.0': T |
932 | 288..294 'self.0': T | 904 | 242..280 '{ ...))); }': () |
933 | 314..352 '{ ...))); }': () | 905 | 252..253 't': &i32 |
934 | 324..325 't': &i32 | 906 | 256..262 'A::foo': fn foo<i32>(&A<i32>) -> &i32 |
935 | 328..334 'A::foo': fn foo<i32>(&A<i32>) -> &i32 | 907 | 256..277 'A::foo...42))))': &i32 |
936 | 328..349 'A::foo...42))))': &i32 | 908 | 263..276 '&&B(B(A(42)))': &&B<B<A<i32>>> |
937 | 335..348 '&&B(B(A(42)))': &&B<B<A<i32>>> | 909 | 264..276 '&B(B(A(42)))': &B<B<A<i32>>> |
938 | 336..348 '&B(B(A(42)))': &B<B<A<i32>>> | 910 | 265..266 'B': B<B<A<i32>>>(B<A<i32>>) -> B<B<A<i32>>> |
939 | 337..338 'B': B<B<A<i32>>>(B<A<i32>>) -> B<B<A<i32>>> | 911 | 265..276 'B(B(A(42)))': B<B<A<i32>>> |
940 | 337..348 'B(B(A(42)))': B<B<A<i32>>> | 912 | 267..268 'B': B<A<i32>>(A<i32>) -> B<A<i32>> |
941 | 339..340 'B': B<A<i32>>(A<i32>) -> B<A<i32>> | 913 | 267..275 'B(A(42))': B<A<i32>> |
942 | 339..347 'B(A(42))': B<A<i32>> | 914 | 269..270 'A': A<i32>(i32) -> A<i32> |
943 | 341..342 'A': A<i32>(i32) -> A<i32> | 915 | 269..274 'A(42)': A<i32> |
944 | 341..346 'A(42)': A<i32> | 916 | 271..273 '42': i32 |
945 | 343..345 '42': i32 | ||
946 | "#]], | 917 | "#]], |
947 | ); | 918 | ); |
948 | } | 919 | } |
@@ -951,62 +922,57 @@ fn infer_argument_autoderef() { | |||
951 | fn infer_method_argument_autoderef() { | 922 | fn infer_method_argument_autoderef() { |
952 | check_infer( | 923 | check_infer( |
953 | r#" | 924 | r#" |
954 | #[lang = "deref"] | 925 | //- minicore: deref |
955 | pub trait Deref { | 926 | use core::ops::Deref; |
956 | type Target; | 927 | struct A<T>(*mut T); |
957 | fn deref(&self) -> &Self::Target; | ||
958 | } | ||
959 | 928 | ||
960 | struct A<T>(*mut T); | 929 | impl<T> A<T> { |
961 | 930 | fn foo(&self, x: &A<T>) -> &T { | |
962 | impl<T> A<T> { | 931 | &*x.0 |
963 | fn foo(&self, x: &A<T>) -> &T { | 932 | } |
964 | &*x.0 | 933 | } |
965 | } | ||
966 | } | ||
967 | 934 | ||
968 | struct B<T>(T); | 935 | struct B<T>(T); |
969 | 936 | ||
970 | impl<T> Deref for B<T> { | 937 | impl<T> Deref for B<T> { |
971 | type Target = T; | 938 | type Target = T; |
972 | fn deref(&self) -> &Self::Target { | 939 | fn deref(&self) -> &Self::Target { |
973 | &self.0 | 940 | &self.0 |
974 | } | 941 | } |
975 | } | 942 | } |
976 | 943 | ||
977 | fn test(a: A<i32>) { | 944 | fn test(a: A<i32>) { |
978 | let t = A(0 as *mut _).foo(&&B(B(a))); | 945 | let t = A(0 as *mut _).foo(&&B(B(a))); |
979 | } | 946 | } |
980 | "#, | 947 | "#, |
981 | expect![[r#" | 948 | expect![[r#" |
982 | 67..71 'self': &Self | 949 | 71..75 'self': &A<T> |
983 | 143..147 'self': &A<T> | 950 | 77..78 'x': &A<T> |
984 | 149..150 'x': &A<T> | 951 | 93..114 '{ ... }': &T |
985 | 165..186 '{ ... }': &T | 952 | 103..108 '&*x.0': &T |
986 | 175..180 '&*x.0': &T | 953 | 104..108 '*x.0': T |
987 | 176..180 '*x.0': T | 954 | 105..106 'x': &A<T> |
988 | 177..178 'x': &A<T> | 955 | 105..108 'x.0': *mut T |
989 | 177..180 'x.0': *mut T | 956 | 195..199 'self': &B<T> |
990 | 267..271 'self': &B<T> | 957 | 218..241 '{ ... }': &T |
991 | 290..313 '{ ... }': &T | 958 | 228..235 '&self.0': &T |
992 | 300..307 '&self.0': &T | 959 | 229..233 'self': &B<T> |
993 | 301..305 'self': &B<T> | 960 | 229..235 'self.0': T |
994 | 301..307 'self.0': T | 961 | 253..254 'a': A<i32> |
995 | 325..326 'a': A<i32> | 962 | 264..310 '{ ...))); }': () |
996 | 336..382 '{ ...))); }': () | 963 | 274..275 't': &i32 |
997 | 346..347 't': &i32 | 964 | 278..279 'A': A<i32>(*mut i32) -> A<i32> |
998 | 350..351 'A': A<i32>(*mut i32) -> A<i32> | 965 | 278..292 'A(0 as *mut _)': A<i32> |
999 | 350..364 'A(0 as *mut _)': A<i32> | 966 | 278..307 'A(0 as...B(a)))': &i32 |
1000 | 350..379 'A(0 as...B(a)))': &i32 | 967 | 280..281 '0': i32 |
1001 | 352..353 '0': i32 | 968 | 280..291 '0 as *mut _': *mut i32 |
1002 | 352..363 '0 as *mut _': *mut i32 | 969 | 297..306 '&&B(B(a))': &&B<B<A<i32>>> |
1003 | 369..378 '&&B(B(a))': &&B<B<A<i32>>> | 970 | 298..306 '&B(B(a))': &B<B<A<i32>>> |
1004 | 370..378 '&B(B(a))': &B<B<A<i32>>> | 971 | 299..300 'B': B<B<A<i32>>>(B<A<i32>>) -> B<B<A<i32>>> |
1005 | 371..372 'B': B<B<A<i32>>>(B<A<i32>>) -> B<B<A<i32>>> | 972 | 299..306 'B(B(a))': B<B<A<i32>>> |
1006 | 371..378 'B(B(a))': B<B<A<i32>>> | 973 | 301..302 'B': B<A<i32>>(A<i32>) -> B<A<i32>> |
1007 | 373..374 'B': B<A<i32>>(A<i32>) -> B<A<i32>> | 974 | 301..305 'B(a)': B<A<i32>> |
1008 | 373..377 'B(a)': B<A<i32>> | 975 | 303..304 'a': A<i32> |
1009 | 375..376 'a': A<i32> | ||
1010 | "#]], | 976 | "#]], |
1011 | ); | 977 | ); |
1012 | } | 978 | } |
@@ -1015,15 +981,15 @@ fn infer_method_argument_autoderef() { | |||
1015 | fn infer_in_elseif() { | 981 | fn infer_in_elseif() { |
1016 | check_infer( | 982 | check_infer( |
1017 | r#" | 983 | r#" |
1018 | struct Foo { field: i32 } | 984 | struct Foo { field: i32 } |
1019 | fn main(foo: Foo) { | 985 | fn main(foo: Foo) { |
1020 | if true { | 986 | if true { |
1021 | 987 | ||
1022 | } else if false { | 988 | } else if false { |
1023 | foo.field | 989 | foo.field |
1024 | } | 990 | } |
1025 | } | 991 | } |
1026 | "#, | 992 | "#, |
1027 | expect![[r#" | 993 | expect![[r#" |
1028 | 34..37 'foo': Foo | 994 | 34..37 'foo': Foo |
1029 | 44..108 '{ ... } }': () | 995 | 44..108 '{ ... } }': () |
@@ -1043,28 +1009,29 @@ fn infer_in_elseif() { | |||
1043 | fn infer_if_match_with_return() { | 1009 | fn infer_if_match_with_return() { |
1044 | check_infer( | 1010 | check_infer( |
1045 | r#" | 1011 | r#" |
1046 | fn foo() { | 1012 | fn foo() { |
1047 | let _x1 = if true { | 1013 | let _x1 = if true { |
1048 | 1 | 1014 | 1 |
1049 | } else { | 1015 | } else { |
1050 | return; | 1016 | return; |
1051 | }; | 1017 | }; |
1052 | let _x2 = if true { | 1018 | let _x2 = if true { |
1053 | 2 | 1019 | 2 |
1054 | } else { | 1020 | } else { |
1055 | return | 1021 | return |
1056 | }; | 1022 | }; |
1057 | let _x3 = match true { | 1023 | let _x3 = match true { |
1058 | true => 3, | 1024 | true => 3, |
1059 | _ => { | 1025 | _ => { |
1060 | return; | 1026 | return; |
1061 | } | 1027 | } |
1062 | }; | 1028 | }; |
1063 | let _x4 = match true { | 1029 | let _x4 = match true { |
1064 | true => 4, | 1030 | true => 4, |
1065 | _ => return | 1031 | _ => return |
1066 | }; | 1032 | }; |
1067 | }"#, | 1033 | } |
1034 | "#, | ||
1068 | expect![[r#" | 1035 | expect![[r#" |
1069 | 9..322 '{ ... }; }': () | 1036 | 9..322 '{ ... }; }': () |
1070 | 19..22 '_x1': i32 | 1037 | 19..22 '_x1': i32 |
@@ -2639,11 +2606,8 @@ fn f() { | |||
2639 | fn infer_boxed_self_receiver() { | 2606 | fn infer_boxed_self_receiver() { |
2640 | check_infer( | 2607 | check_infer( |
2641 | r#" | 2608 | r#" |
2642 | #[lang = "deref"] | 2609 | //- minicore: deref |
2643 | pub trait Deref { | 2610 | use core::ops::Deref; |
2644 | type Target; | ||
2645 | fn deref(&self) -> &Self::Target; | ||
2646 | } | ||
2647 | 2611 | ||
2648 | struct Box<T>(T); | 2612 | struct Box<T>(T); |
2649 | 2613 | ||
@@ -2675,40 +2639,39 @@ fn main() { | |||
2675 | } | 2639 | } |
2676 | "#, | 2640 | "#, |
2677 | expect![[r#" | 2641 | expect![[r#" |
2678 | 67..71 'self': &Self | 2642 | 104..108 'self': &Box<T> |
2679 | 175..179 'self': &Box<T> | 2643 | 188..192 'self': &Box<Foo<T>> |
2680 | 259..263 'self': &Box<Foo<T>> | 2644 | 218..220 '{}': () |
2681 | 289..291 '{}': () | 2645 | 242..246 'self': &Box<Foo<T>> |
2682 | 313..317 'self': &Box<Foo<T>> | 2646 | 275..277 '{}': () |
2683 | 346..348 '{}': () | 2647 | 297..301 'self': Box<Foo<T>> |
2684 | 368..372 'self': Box<Foo<T>> | 2648 | 322..324 '{}': () |
2685 | 393..395 '{}': () | 2649 | 338..559 '{ ...r(); }': () |
2686 | 409..630 '{ ...r(); }': () | 2650 | 348..353 'boxed': Box<Foo<i32>> |
2687 | 419..424 'boxed': Box<Foo<i32>> | 2651 | 356..359 'Box': Box<Foo<i32>>(Foo<i32>) -> Box<Foo<i32>> |
2688 | 427..430 'Box': Box<Foo<i32>>(Foo<i32>) -> Box<Foo<i32>> | 2652 | 356..371 'Box(Foo(0_i32))': Box<Foo<i32>> |
2689 | 427..442 'Box(Foo(0_i32))': Box<Foo<i32>> | 2653 | 360..363 'Foo': Foo<i32>(i32) -> Foo<i32> |
2690 | 431..434 'Foo': Foo<i32>(i32) -> Foo<i32> | 2654 | 360..370 'Foo(0_i32)': Foo<i32> |
2691 | 431..441 'Foo(0_i32)': Foo<i32> | 2655 | 364..369 '0_i32': i32 |
2692 | 435..440 '0_i32': i32 | 2656 | 382..386 'bad1': &i32 |
2693 | 453..457 'bad1': &i32 | 2657 | 389..394 'boxed': Box<Foo<i32>> |
2694 | 460..465 'boxed': Box<Foo<i32>> | 2658 | 389..406 'boxed....nner()': &i32 |
2695 | 460..477 'boxed....nner()': &i32 | 2659 | 416..421 'good1': &i32 |
2696 | 487..492 'good1': &i32 | 2660 | 424..438 'Foo::get_inner': fn get_inner<i32>(&Box<Foo<i32>>) -> &i32 |
2697 | 495..509 'Foo::get_inner': fn get_inner<i32>(&Box<Foo<i32>>) -> &i32 | 2661 | 424..446 'Foo::g...boxed)': &i32 |
2698 | 495..517 'Foo::g...boxed)': &i32 | 2662 | 439..445 '&boxed': &Box<Foo<i32>> |
2699 | 510..516 '&boxed': &Box<Foo<i32>> | 2663 | 440..445 'boxed': Box<Foo<i32>> |
2700 | 511..516 'boxed': Box<Foo<i32>> | 2664 | 457..461 'bad2': &Foo<i32> |
2701 | 528..532 'bad2': &Foo<i32> | 2665 | 464..469 'boxed': Box<Foo<i32>> |
2702 | 535..540 'boxed': Box<Foo<i32>> | 2666 | 464..480 'boxed....self()': &Foo<i32> |
2703 | 535..551 'boxed....self()': &Foo<i32> | 2667 | 490..495 'good2': &Foo<i32> |
2704 | 561..566 'good2': &Foo<i32> | 2668 | 498..511 'Foo::get_self': fn get_self<i32>(&Box<Foo<i32>>) -> &Foo<i32> |
2705 | 569..582 'Foo::get_self': fn get_self<i32>(&Box<Foo<i32>>) -> &Foo<i32> | 2669 | 498..519 'Foo::g...boxed)': &Foo<i32> |
2706 | 569..590 'Foo::g...boxed)': &Foo<i32> | 2670 | 512..518 '&boxed': &Box<Foo<i32>> |
2707 | 583..589 '&boxed': &Box<Foo<i32>> | 2671 | 513..518 'boxed': Box<Foo<i32>> |
2708 | 584..589 'boxed': Box<Foo<i32>> | 2672 | 530..535 'inner': Foo<i32> |
2709 | 601..606 'inner': Foo<i32> | 2673 | 538..543 'boxed': Box<Foo<i32>> |
2710 | 609..614 'boxed': Box<Foo<i32>> | 2674 | 538..556 'boxed....nner()': Foo<i32> |
2711 | 609..627 'boxed....nner()': Foo<i32> | ||
2712 | "#]], | 2675 | "#]], |
2713 | ); | 2676 | ); |
2714 | } | 2677 | } |
diff --git a/crates/hir_ty/src/tests/traits.rs b/crates/hir_ty/src/tests/traits.rs index 6bcede4c4..65fed02d2 100644 --- a/crates/hir_ty/src/tests/traits.rs +++ b/crates/hir_ty/src/tests/traits.rs | |||
@@ -6,10 +6,10 @@ use super::{check_infer, check_infer_with_mismatches, check_types}; | |||
6 | fn infer_await() { | 6 | fn infer_await() { |
7 | check_types( | 7 | check_types( |
8 | r#" | 8 | r#" |
9 | //- /main.rs crate:main deps:core | 9 | //- minicore: future |
10 | struct IntFuture; | 10 | struct IntFuture; |
11 | 11 | ||
12 | impl Future for IntFuture { | 12 | impl core::future::Future for IntFuture { |
13 | type Output = u64; | 13 | type Output = u64; |
14 | } | 14 | } |
15 | 15 | ||
@@ -18,16 +18,6 @@ fn test() { | |||
18 | let v = r.await; | 18 | let v = r.await; |
19 | v; | 19 | v; |
20 | } //^ u64 | 20 | } //^ u64 |
21 | |||
22 | //- /core.rs crate:core | ||
23 | pub mod prelude { | ||
24 | pub mod rust_2018 { | ||
25 | #[lang = "future_trait"] | ||
26 | pub trait Future { | ||
27 | type Output; | ||
28 | } | ||
29 | } | ||
30 | } | ||
31 | "#, | 21 | "#, |
32 | ); | 22 | ); |
33 | } | 23 | } |
@@ -36,25 +26,14 @@ pub mod prelude { | |||
36 | fn infer_async() { | 26 | fn infer_async() { |
37 | check_types( | 27 | check_types( |
38 | r#" | 28 | r#" |
39 | //- /main.rs crate:main deps:core | 29 | //- minicore: future |
40 | async fn foo() -> u64 { | 30 | async fn foo() -> u64 { 128 } |
41 | 128 | ||
42 | } | ||
43 | 31 | ||
44 | fn test() { | 32 | fn test() { |
45 | let r = foo(); | 33 | let r = foo(); |
46 | let v = r.await; | 34 | let v = r.await; |
47 | v; | 35 | v; |
48 | } //^ u64 | 36 | } //^ u64 |
49 | |||
50 | //- /core.rs crate:core | ||
51 | #[prelude_import] use future::*; | ||
52 | mod future { | ||
53 | #[lang = "future_trait"] | ||
54 | trait Future { | ||
55 | type Output; | ||
56 | } | ||
57 | } | ||
58 | "#, | 37 | "#, |
59 | ); | 38 | ); |
60 | } | 39 | } |
@@ -63,24 +42,13 @@ mod future { | |||
63 | fn infer_desugar_async() { | 42 | fn infer_desugar_async() { |
64 | check_types( | 43 | check_types( |
65 | r#" | 44 | r#" |
66 | //- /main.rs crate:main deps:core | 45 | //- minicore: future |
67 | async fn foo() -> u64 { | 46 | async fn foo() -> u64 { 128 } |
68 | 128 | ||
69 | } | ||
70 | 47 | ||
71 | fn test() { | 48 | fn test() { |
72 | let r = foo(); | 49 | let r = foo(); |
73 | r; | 50 | r; |
74 | } //^ impl Future<Output = u64> | 51 | } //^ impl Future<Output = u64> |
75 | |||
76 | //- /core.rs crate:core | ||
77 | #[prelude_import] use future::*; | ||
78 | mod future { | ||
79 | trait Future { | ||
80 | type Output; | ||
81 | } | ||
82 | } | ||
83 | |||
84 | "#, | 52 | "#, |
85 | ); | 53 | ); |
86 | } | 54 | } |
@@ -89,7 +57,7 @@ mod future { | |||
89 | fn infer_async_block() { | 57 | fn infer_async_block() { |
90 | check_types( | 58 | check_types( |
91 | r#" | 59 | r#" |
92 | //- /main.rs crate:main deps:core | 60 | //- minicore: future, option |
93 | async fn test() { | 61 | async fn test() { |
94 | let a = async { 42 }; | 62 | let a = async { 42 }; |
95 | a; | 63 | a; |
@@ -101,7 +69,7 @@ async fn test() { | |||
101 | b; | 69 | b; |
102 | // ^ () | 70 | // ^ () |
103 | let c = async { | 71 | let c = async { |
104 | let y = Option::None; | 72 | let y = None; |
105 | y | 73 | y |
106 | // ^ Option<u64> | 74 | // ^ Option<u64> |
107 | }; | 75 | }; |
@@ -109,18 +77,6 @@ async fn test() { | |||
109 | c; | 77 | c; |
110 | // ^ impl Future<Output = Option<u64>> | 78 | // ^ impl Future<Output = Option<u64>> |
111 | } | 79 | } |
112 | |||
113 | enum Option<T> { None, Some(T) } | ||
114 | |||
115 | //- /core.rs crate:core | ||
116 | #[prelude_import] use future::*; | ||
117 | mod future { | ||
118 | #[lang = "future_trait"] | ||
119 | trait Future { | ||
120 | type Output; | ||
121 | } | ||
122 | } | ||
123 | |||
124 | "#, | 80 | "#, |
125 | ); | 81 | ); |
126 | } | 82 | } |
@@ -704,14 +660,9 @@ mod ops { | |||
704 | fn deref_trait() { | 660 | fn deref_trait() { |
705 | check_types( | 661 | check_types( |
706 | r#" | 662 | r#" |
707 | #[lang = "deref"] | 663 | //- minicore: deref |
708 | trait Deref { | ||
709 | type Target; | ||
710 | fn deref(&self) -> &Self::Target; | ||
711 | } | ||
712 | |||
713 | struct Arc<T>; | 664 | struct Arc<T>; |
714 | impl<T> Deref for Arc<T> { | 665 | impl<T> core::ops::Deref for Arc<T> { |
715 | type Target = T; | 666 | type Target = T; |
716 | } | 667 | } |
717 | 668 | ||
@@ -731,16 +682,10 @@ fn test(s: Arc<S>) { | |||
731 | fn deref_trait_with_inference_var() { | 682 | fn deref_trait_with_inference_var() { |
732 | check_types( | 683 | check_types( |
733 | r#" | 684 | r#" |
734 | //- /main.rs | 685 | //- minicore: deref |
735 | #[lang = "deref"] | ||
736 | trait Deref { | ||
737 | type Target; | ||
738 | fn deref(&self) -> &Self::Target; | ||
739 | } | ||
740 | |||
741 | struct Arc<T>; | 686 | struct Arc<T>; |
742 | fn new_arc<T>() -> Arc<T> {} | 687 | fn new_arc<T>() -> Arc<T> {} |
743 | impl<T> Deref for Arc<T> { | 688 | impl<T> core::ops::Deref for Arc<T> { |
744 | type Target = T; | 689 | type Target = T; |
745 | } | 690 | } |
746 | 691 | ||
@@ -761,15 +706,10 @@ fn test() { | |||
761 | fn deref_trait_infinite_recursion() { | 706 | fn deref_trait_infinite_recursion() { |
762 | check_types( | 707 | check_types( |
763 | r#" | 708 | r#" |
764 | #[lang = "deref"] | 709 | //- minicore: deref |
765 | trait Deref { | ||
766 | type Target; | ||
767 | fn deref(&self) -> &Self::Target; | ||
768 | } | ||
769 | |||
770 | struct S; | 710 | struct S; |
771 | 711 | ||
772 | impl Deref for S { | 712 | impl core::ops::Deref for S { |
773 | type Target = S; | 713 | type Target = S; |
774 | } | 714 | } |
775 | 715 | ||
@@ -784,14 +724,9 @@ fn test(s: S) { | |||
784 | fn deref_trait_with_question_mark_size() { | 724 | fn deref_trait_with_question_mark_size() { |
785 | check_types( | 725 | check_types( |
786 | r#" | 726 | r#" |
787 | #[lang = "deref"] | 727 | //- minicore: deref |
788 | trait Deref { | ||
789 | type Target; | ||
790 | fn deref(&self) -> &Self::Target; | ||
791 | } | ||
792 | |||
793 | struct Arc<T>; | 728 | struct Arc<T>; |
794 | impl<T> Deref for Arc<T> { | 729 | impl<T: ?Sized> core::ops::Deref for Arc<T> { |
795 | type Target = T; | 730 | type Target = T; |
796 | } | 731 | } |
797 | 732 | ||
@@ -1475,7 +1410,6 @@ fn test( | |||
1475 | } | 1410 | } |
1476 | 1411 | ||
1477 | #[test] | 1412 | #[test] |
1478 | #[ignore] | ||
1479 | fn error_bound_chalk() { | 1413 | fn error_bound_chalk() { |
1480 | check_types( | 1414 | check_types( |
1481 | r#" | 1415 | r#" |
@@ -2626,12 +2560,9 @@ fn test<T: Trait>() { | |||
2626 | fn dyn_trait_through_chalk() { | 2560 | fn dyn_trait_through_chalk() { |
2627 | check_types( | 2561 | check_types( |
2628 | r#" | 2562 | r#" |
2563 | //- minicore: deref | ||
2629 | struct Box<T> {} | 2564 | struct Box<T> {} |
2630 | #[lang = "deref"] | 2565 | impl<T> core::ops::Deref for Box<T> { |
2631 | trait Deref { | ||
2632 | type Target; | ||
2633 | } | ||
2634 | impl<T> Deref for Box<T> { | ||
2635 | type Target = T; | 2566 | type Target = T; |
2636 | } | 2567 | } |
2637 | trait Trait { | 2568 | trait Trait { |
@@ -3696,16 +3627,7 @@ impl foo::Foo for u32 { | |||
3696 | fn infer_async_ret_type() { | 3627 | fn infer_async_ret_type() { |
3697 | check_types( | 3628 | check_types( |
3698 | r#" | 3629 | r#" |
3699 | //- /main.rs crate:main deps:core | 3630 | //- minicore: future, result |
3700 | |||
3701 | enum Result<T, E> { | ||
3702 | Ok(T), | ||
3703 | Err(E), | ||
3704 | } | ||
3705 | |||
3706 | use Result::*; | ||
3707 | |||
3708 | |||
3709 | struct Fooey; | 3631 | struct Fooey; |
3710 | 3632 | ||
3711 | impl Fooey { | 3633 | impl Fooey { |
@@ -3728,15 +3650,6 @@ async fn get_accounts() -> Result<u32, ()> { | |||
3728 | // ^ u32 | 3650 | // ^ u32 |
3729 | Ok(ret) | 3651 | Ok(ret) |
3730 | } | 3652 | } |
3731 | |||
3732 | //- /core.rs crate:core | ||
3733 | #[prelude_import] use future::*; | ||
3734 | mod future { | ||
3735 | #[lang = "future_trait"] | ||
3736 | trait Future { | ||
3737 | type Output; | ||
3738 | } | ||
3739 | } | ||
3740 | "#, | 3653 | "#, |
3741 | ); | 3654 | ); |
3742 | } | 3655 | } |
diff --git a/crates/ide/Cargo.toml b/crates/ide/Cargo.toml index f12928225..0e8447394 100644 --- a/crates/ide/Cargo.toml +++ b/crates/ide/Cargo.toml | |||
@@ -29,6 +29,7 @@ ide_db = { path = "../ide_db", version = "0.0.0" } | |||
29 | cfg = { path = "../cfg", version = "0.0.0" } | 29 | cfg = { path = "../cfg", version = "0.0.0" } |
30 | profile = { path = "../profile", version = "0.0.0" } | 30 | profile = { path = "../profile", version = "0.0.0" } |
31 | ide_assists = { path = "../ide_assists", version = "0.0.0" } | 31 | ide_assists = { path = "../ide_assists", version = "0.0.0" } |
32 | ide_diagnostics = { path = "../ide_diagnostics", version = "0.0.0" } | ||
32 | ide_ssr = { path = "../ide_ssr", version = "0.0.0" } | 33 | ide_ssr = { path = "../ide_ssr", version = "0.0.0" } |
33 | ide_completion = { path = "../ide_completion", version = "0.0.0" } | 34 | ide_completion = { path = "../ide_completion", version = "0.0.0" } |
34 | 35 | ||
diff --git a/crates/ide/src/diagnostics.rs b/crates/ide/src/diagnostics.rs deleted file mode 100644 index 815a633e5..000000000 --- a/crates/ide/src/diagnostics.rs +++ /dev/null | |||
@@ -1,498 +0,0 @@ | |||
1 | //! Collects diagnostics & fixits for a single file. | ||
2 | //! | ||
3 | //! The tricky bit here is that diagnostics are produced by hir in terms of | ||
4 | //! macro-expanded files, but we need to present them to the users in terms of | ||
5 | //! original files. So we need to map the ranges. | ||
6 | |||
7 | mod break_outside_of_loop; | ||
8 | mod inactive_code; | ||
9 | mod incorrect_case; | ||
10 | mod macro_error; | ||
11 | mod mismatched_arg_count; | ||
12 | mod missing_fields; | ||
13 | mod missing_match_arms; | ||
14 | mod missing_ok_or_some_in_tail_expr; | ||
15 | mod missing_unsafe; | ||
16 | mod no_such_field; | ||
17 | mod remove_this_semicolon; | ||
18 | mod replace_filter_map_next_with_find_map; | ||
19 | mod unimplemented_builtin_macro; | ||
20 | mod unlinked_file; | ||
21 | mod unresolved_extern_crate; | ||
22 | mod unresolved_import; | ||
23 | mod unresolved_macro_call; | ||
24 | mod unresolved_module; | ||
25 | mod unresolved_proc_macro; | ||
26 | |||
27 | mod field_shorthand; | ||
28 | |||
29 | use hir::{diagnostics::AnyDiagnostic, Semantics}; | ||
30 | use ide_assists::AssistResolveStrategy; | ||
31 | use ide_db::{base_db::SourceDatabase, RootDatabase}; | ||
32 | use itertools::Itertools; | ||
33 | use rustc_hash::FxHashSet; | ||
34 | use syntax::{ | ||
35 | ast::{self, AstNode}, | ||
36 | SyntaxNode, TextRange, | ||
37 | }; | ||
38 | use text_edit::TextEdit; | ||
39 | use unlinked_file::UnlinkedFile; | ||
40 | |||
41 | use crate::{Assist, AssistId, AssistKind, FileId, Label, SourceChange}; | ||
42 | |||
43 | #[derive(Copy, Clone, Debug, PartialEq)] | ||
44 | pub struct DiagnosticCode(pub &'static str); | ||
45 | |||
46 | impl DiagnosticCode { | ||
47 | pub fn as_str(&self) -> &str { | ||
48 | self.0 | ||
49 | } | ||
50 | } | ||
51 | |||
52 | #[derive(Debug)] | ||
53 | pub struct Diagnostic { | ||
54 | pub code: DiagnosticCode, | ||
55 | pub message: String, | ||
56 | pub range: TextRange, | ||
57 | pub severity: Severity, | ||
58 | pub unused: bool, | ||
59 | pub experimental: bool, | ||
60 | pub fixes: Option<Vec<Assist>>, | ||
61 | } | ||
62 | |||
63 | impl Diagnostic { | ||
64 | fn new(code: &'static str, message: impl Into<String>, range: TextRange) -> Diagnostic { | ||
65 | let message = message.into(); | ||
66 | Diagnostic { | ||
67 | code: DiagnosticCode(code), | ||
68 | message, | ||
69 | range, | ||
70 | severity: Severity::Error, | ||
71 | unused: false, | ||
72 | experimental: false, | ||
73 | fixes: None, | ||
74 | } | ||
75 | } | ||
76 | |||
77 | fn experimental(mut self) -> Diagnostic { | ||
78 | self.experimental = true; | ||
79 | self | ||
80 | } | ||
81 | |||
82 | fn severity(mut self, severity: Severity) -> Diagnostic { | ||
83 | self.severity = severity; | ||
84 | self | ||
85 | } | ||
86 | |||
87 | fn with_fixes(mut self, fixes: Option<Vec<Assist>>) -> Diagnostic { | ||
88 | self.fixes = fixes; | ||
89 | self | ||
90 | } | ||
91 | |||
92 | fn with_unused(mut self, unused: bool) -> Diagnostic { | ||
93 | self.unused = unused; | ||
94 | self | ||
95 | } | ||
96 | } | ||
97 | |||
98 | #[derive(Debug, Copy, Clone)] | ||
99 | pub enum Severity { | ||
100 | Error, | ||
101 | WeakWarning, | ||
102 | } | ||
103 | |||
104 | #[derive(Default, Debug, Clone)] | ||
105 | pub struct DiagnosticsConfig { | ||
106 | pub disable_experimental: bool, | ||
107 | pub disabled: FxHashSet<String>, | ||
108 | } | ||
109 | |||
110 | struct DiagnosticsContext<'a> { | ||
111 | config: &'a DiagnosticsConfig, | ||
112 | sema: Semantics<'a, RootDatabase>, | ||
113 | resolve: &'a AssistResolveStrategy, | ||
114 | } | ||
115 | |||
116 | pub(crate) fn diagnostics( | ||
117 | db: &RootDatabase, | ||
118 | config: &DiagnosticsConfig, | ||
119 | resolve: &AssistResolveStrategy, | ||
120 | file_id: FileId, | ||
121 | ) -> Vec<Diagnostic> { | ||
122 | let _p = profile::span("diagnostics"); | ||
123 | let sema = Semantics::new(db); | ||
124 | let parse = db.parse(file_id); | ||
125 | let mut res = Vec::new(); | ||
126 | |||
127 | // [#34344] Only take first 128 errors to prevent slowing down editor/ide, the number 128 is chosen arbitrarily. | ||
128 | res.extend( | ||
129 | parse.errors().iter().take(128).map(|err| { | ||
130 | Diagnostic::new("syntax-error", format!("Syntax Error: {}", err), err.range()) | ||
131 | }), | ||
132 | ); | ||
133 | |||
134 | for node in parse.tree().syntax().descendants() { | ||
135 | check_unnecessary_braces_in_use_statement(&mut res, file_id, &node); | ||
136 | field_shorthand::check(&mut res, file_id, &node); | ||
137 | } | ||
138 | |||
139 | let mut diags = Vec::new(); | ||
140 | let module = sema.to_module_def(file_id); | ||
141 | if let Some(m) = module { | ||
142 | m.diagnostics(db, &mut diags) | ||
143 | } | ||
144 | |||
145 | let ctx = DiagnosticsContext { config, sema, resolve }; | ||
146 | if module.is_none() { | ||
147 | let d = UnlinkedFile { file: file_id }; | ||
148 | let d = unlinked_file::unlinked_file(&ctx, &d); | ||
149 | res.push(d) | ||
150 | } | ||
151 | |||
152 | for diag in diags { | ||
153 | #[rustfmt::skip] | ||
154 | let d = match diag { | ||
155 | AnyDiagnostic::BreakOutsideOfLoop(d) => break_outside_of_loop::break_outside_of_loop(&ctx, &d), | ||
156 | AnyDiagnostic::IncorrectCase(d) => incorrect_case::incorrect_case(&ctx, &d), | ||
157 | AnyDiagnostic::MacroError(d) => macro_error::macro_error(&ctx, &d), | ||
158 | AnyDiagnostic::MismatchedArgCount(d) => mismatched_arg_count::mismatched_arg_count(&ctx, &d), | ||
159 | AnyDiagnostic::MissingFields(d) => missing_fields::missing_fields(&ctx, &d), | ||
160 | AnyDiagnostic::MissingMatchArms(d) => missing_match_arms::missing_match_arms(&ctx, &d), | ||
161 | AnyDiagnostic::MissingOkOrSomeInTailExpr(d) => missing_ok_or_some_in_tail_expr::missing_ok_or_some_in_tail_expr(&ctx, &d), | ||
162 | AnyDiagnostic::MissingUnsafe(d) => missing_unsafe::missing_unsafe(&ctx, &d), | ||
163 | AnyDiagnostic::NoSuchField(d) => no_such_field::no_such_field(&ctx, &d), | ||
164 | AnyDiagnostic::RemoveThisSemicolon(d) => remove_this_semicolon::remove_this_semicolon(&ctx, &d), | ||
165 | AnyDiagnostic::ReplaceFilterMapNextWithFindMap(d) => replace_filter_map_next_with_find_map::replace_filter_map_next_with_find_map(&ctx, &d), | ||
166 | AnyDiagnostic::UnimplementedBuiltinMacro(d) => unimplemented_builtin_macro::unimplemented_builtin_macro(&ctx, &d), | ||
167 | AnyDiagnostic::UnresolvedExternCrate(d) => unresolved_extern_crate::unresolved_extern_crate(&ctx, &d), | ||
168 | AnyDiagnostic::UnresolvedImport(d) => unresolved_import::unresolved_import(&ctx, &d), | ||
169 | AnyDiagnostic::UnresolvedMacroCall(d) => unresolved_macro_call::unresolved_macro_call(&ctx, &d), | ||
170 | AnyDiagnostic::UnresolvedModule(d) => unresolved_module::unresolved_module(&ctx, &d), | ||
171 | AnyDiagnostic::UnresolvedProcMacro(d) => unresolved_proc_macro::unresolved_proc_macro(&ctx, &d), | ||
172 | |||
173 | AnyDiagnostic::InactiveCode(d) => match inactive_code::inactive_code(&ctx, &d) { | ||
174 | Some(it) => it, | ||
175 | None => continue, | ||
176 | } | ||
177 | }; | ||
178 | res.push(d) | ||
179 | } | ||
180 | |||
181 | res.retain(|d| { | ||
182 | !ctx.config.disabled.contains(d.code.as_str()) | ||
183 | && !(ctx.config.disable_experimental && d.experimental) | ||
184 | }); | ||
185 | |||
186 | res | ||
187 | } | ||
188 | |||
189 | fn check_unnecessary_braces_in_use_statement( | ||
190 | acc: &mut Vec<Diagnostic>, | ||
191 | file_id: FileId, | ||
192 | node: &SyntaxNode, | ||
193 | ) -> Option<()> { | ||
194 | let use_tree_list = ast::UseTreeList::cast(node.clone())?; | ||
195 | if let Some((single_use_tree,)) = use_tree_list.use_trees().collect_tuple() { | ||
196 | // If there is a comment inside the bracketed `use`, | ||
197 | // assume it is a commented out module path and don't show diagnostic. | ||
198 | if use_tree_list.has_inner_comment() { | ||
199 | return Some(()); | ||
200 | } | ||
201 | |||
202 | let use_range = use_tree_list.syntax().text_range(); | ||
203 | let edit = | ||
204 | text_edit_for_remove_unnecessary_braces_with_self_in_use_statement(&single_use_tree) | ||
205 | .unwrap_or_else(|| { | ||
206 | let to_replace = single_use_tree.syntax().text().to_string(); | ||
207 | let mut edit_builder = TextEdit::builder(); | ||
208 | edit_builder.delete(use_range); | ||
209 | edit_builder.insert(use_range.start(), to_replace); | ||
210 | edit_builder.finish() | ||
211 | }); | ||
212 | |||
213 | acc.push( | ||
214 | Diagnostic::new( | ||
215 | "unnecessary-braces", | ||
216 | "Unnecessary braces in use statement".to_string(), | ||
217 | use_range, | ||
218 | ) | ||
219 | .severity(Severity::WeakWarning) | ||
220 | .with_fixes(Some(vec![fix( | ||
221 | "remove_braces", | ||
222 | "Remove unnecessary braces", | ||
223 | SourceChange::from_text_edit(file_id, edit), | ||
224 | use_range, | ||
225 | )])), | ||
226 | ); | ||
227 | } | ||
228 | |||
229 | Some(()) | ||
230 | } | ||
231 | |||
232 | fn text_edit_for_remove_unnecessary_braces_with_self_in_use_statement( | ||
233 | single_use_tree: &ast::UseTree, | ||
234 | ) -> Option<TextEdit> { | ||
235 | let use_tree_list_node = single_use_tree.syntax().parent()?; | ||
236 | if single_use_tree.path()?.segment()?.self_token().is_some() { | ||
237 | let start = use_tree_list_node.prev_sibling_or_token()?.text_range().start(); | ||
238 | let end = use_tree_list_node.text_range().end(); | ||
239 | return Some(TextEdit::delete(TextRange::new(start, end))); | ||
240 | } | ||
241 | None | ||
242 | } | ||
243 | |||
244 | fn fix(id: &'static str, label: &str, source_change: SourceChange, target: TextRange) -> Assist { | ||
245 | let mut res = unresolved_fix(id, label, target); | ||
246 | res.source_change = Some(source_change); | ||
247 | res | ||
248 | } | ||
249 | |||
250 | fn unresolved_fix(id: &'static str, label: &str, target: TextRange) -> Assist { | ||
251 | assert!(!id.contains(' ')); | ||
252 | Assist { | ||
253 | id: AssistId(id, AssistKind::QuickFix), | ||
254 | label: Label::new(label), | ||
255 | group: None, | ||
256 | target, | ||
257 | source_change: None, | ||
258 | } | ||
259 | } | ||
260 | |||
261 | #[cfg(test)] | ||
262 | mod tests { | ||
263 | use expect_test::Expect; | ||
264 | use ide_assists::AssistResolveStrategy; | ||
265 | use stdx::trim_indent; | ||
266 | use test_utils::{assert_eq_text, extract_annotations}; | ||
267 | |||
268 | use crate::{fixture, DiagnosticsConfig}; | ||
269 | |||
270 | /// Takes a multi-file input fixture with annotated cursor positions, | ||
271 | /// and checks that: | ||
272 | /// * a diagnostic is produced | ||
273 | /// * the first diagnostic fix trigger range touches the input cursor position | ||
274 | /// * that the contents of the file containing the cursor match `after` after the diagnostic fix is applied | ||
275 | #[track_caller] | ||
276 | pub(crate) fn check_fix(ra_fixture_before: &str, ra_fixture_after: &str) { | ||
277 | check_nth_fix(0, ra_fixture_before, ra_fixture_after); | ||
278 | } | ||
279 | /// Takes a multi-file input fixture with annotated cursor positions, | ||
280 | /// and checks that: | ||
281 | /// * a diagnostic is produced | ||
282 | /// * every diagnostic fixes trigger range touches the input cursor position | ||
283 | /// * that the contents of the file containing the cursor match `after` after each diagnostic fix is applied | ||
284 | pub(crate) fn check_fixes(ra_fixture_before: &str, ra_fixtures_after: Vec<&str>) { | ||
285 | for (i, ra_fixture_after) in ra_fixtures_after.iter().enumerate() { | ||
286 | check_nth_fix(i, ra_fixture_before, ra_fixture_after) | ||
287 | } | ||
288 | } | ||
289 | |||
290 | #[track_caller] | ||
291 | fn check_nth_fix(nth: usize, ra_fixture_before: &str, ra_fixture_after: &str) { | ||
292 | let after = trim_indent(ra_fixture_after); | ||
293 | |||
294 | let (analysis, file_position) = fixture::position(ra_fixture_before); | ||
295 | let diagnostic = analysis | ||
296 | .diagnostics( | ||
297 | &DiagnosticsConfig::default(), | ||
298 | AssistResolveStrategy::All, | ||
299 | file_position.file_id, | ||
300 | ) | ||
301 | .unwrap() | ||
302 | .pop() | ||
303 | .expect("no diagnostics"); | ||
304 | let fix = &diagnostic.fixes.expect("diagnostic misses fixes")[nth]; | ||
305 | let actual = { | ||
306 | let source_change = fix.source_change.as_ref().unwrap(); | ||
307 | let file_id = *source_change.source_file_edits.keys().next().unwrap(); | ||
308 | let mut actual = analysis.file_text(file_id).unwrap().to_string(); | ||
309 | |||
310 | for edit in source_change.source_file_edits.values() { | ||
311 | edit.apply(&mut actual); | ||
312 | } | ||
313 | actual | ||
314 | }; | ||
315 | |||
316 | assert_eq_text!(&after, &actual); | ||
317 | assert!( | ||
318 | fix.target.contains_inclusive(file_position.offset), | ||
319 | "diagnostic fix range {:?} does not touch cursor position {:?}", | ||
320 | fix.target, | ||
321 | file_position.offset | ||
322 | ); | ||
323 | } | ||
324 | |||
325 | /// Checks that there's a diagnostic *without* fix at `$0`. | ||
326 | pub(crate) fn check_no_fix(ra_fixture: &str) { | ||
327 | let (analysis, file_position) = fixture::position(ra_fixture); | ||
328 | let diagnostic = analysis | ||
329 | .diagnostics( | ||
330 | &DiagnosticsConfig::default(), | ||
331 | AssistResolveStrategy::All, | ||
332 | file_position.file_id, | ||
333 | ) | ||
334 | .unwrap() | ||
335 | .pop() | ||
336 | .unwrap(); | ||
337 | assert!(diagnostic.fixes.is_none(), "got a fix when none was expected: {:?}", diagnostic); | ||
338 | } | ||
339 | |||
340 | pub(crate) fn check_expect(ra_fixture: &str, expect: Expect) { | ||
341 | let (analysis, file_id) = fixture::file(ra_fixture); | ||
342 | let diagnostics = analysis | ||
343 | .diagnostics(&DiagnosticsConfig::default(), AssistResolveStrategy::All, file_id) | ||
344 | .unwrap(); | ||
345 | expect.assert_debug_eq(&diagnostics) | ||
346 | } | ||
347 | |||
348 | #[track_caller] | ||
349 | pub(crate) fn check_diagnostics(ra_fixture: &str) { | ||
350 | let mut config = DiagnosticsConfig::default(); | ||
351 | config.disabled.insert("inactive-code".to_string()); | ||
352 | check_diagnostics_with_config(config, ra_fixture) | ||
353 | } | ||
354 | |||
355 | #[track_caller] | ||
356 | pub(crate) fn check_diagnostics_with_config(config: DiagnosticsConfig, ra_fixture: &str) { | ||
357 | let (analysis, files) = fixture::files(ra_fixture); | ||
358 | for file_id in files { | ||
359 | let diagnostics = | ||
360 | analysis.diagnostics(&config, AssistResolveStrategy::All, file_id).unwrap(); | ||
361 | |||
362 | let expected = extract_annotations(&*analysis.file_text(file_id).unwrap()); | ||
363 | let mut actual = | ||
364 | diagnostics.into_iter().map(|d| (d.range, d.message)).collect::<Vec<_>>(); | ||
365 | actual.sort_by_key(|(range, _)| range.start()); | ||
366 | assert_eq!(expected, actual); | ||
367 | } | ||
368 | } | ||
369 | |||
370 | #[test] | ||
371 | fn test_check_unnecessary_braces_in_use_statement() { | ||
372 | check_diagnostics( | ||
373 | r#" | ||
374 | use a; | ||
375 | use a::{c, d::e}; | ||
376 | |||
377 | mod a { | ||
378 | mod c {} | ||
379 | mod d { | ||
380 | mod e {} | ||
381 | } | ||
382 | } | ||
383 | "#, | ||
384 | ); | ||
385 | check_diagnostics( | ||
386 | r#" | ||
387 | use a; | ||
388 | use a::{ | ||
389 | c, | ||
390 | // d::e | ||
391 | }; | ||
392 | |||
393 | mod a { | ||
394 | mod c {} | ||
395 | mod d { | ||
396 | mod e {} | ||
397 | } | ||
398 | } | ||
399 | "#, | ||
400 | ); | ||
401 | check_fix( | ||
402 | r" | ||
403 | mod b {} | ||
404 | use {$0b}; | ||
405 | ", | ||
406 | r" | ||
407 | mod b {} | ||
408 | use b; | ||
409 | ", | ||
410 | ); | ||
411 | check_fix( | ||
412 | r" | ||
413 | mod b {} | ||
414 | use {b$0}; | ||
415 | ", | ||
416 | r" | ||
417 | mod b {} | ||
418 | use b; | ||
419 | ", | ||
420 | ); | ||
421 | check_fix( | ||
422 | r" | ||
423 | mod a { mod c {} } | ||
424 | use a::{c$0}; | ||
425 | ", | ||
426 | r" | ||
427 | mod a { mod c {} } | ||
428 | use a::c; | ||
429 | ", | ||
430 | ); | ||
431 | check_fix( | ||
432 | r" | ||
433 | mod a {} | ||
434 | use a::{self$0}; | ||
435 | ", | ||
436 | r" | ||
437 | mod a {} | ||
438 | use a; | ||
439 | ", | ||
440 | ); | ||
441 | check_fix( | ||
442 | r" | ||
443 | mod a { mod c {} mod d { mod e {} } } | ||
444 | use a::{c, d::{e$0}}; | ||
445 | ", | ||
446 | r" | ||
447 | mod a { mod c {} mod d { mod e {} } } | ||
448 | use a::{c, d::e}; | ||
449 | ", | ||
450 | ); | ||
451 | } | ||
452 | |||
453 | #[test] | ||
454 | fn test_disabled_diagnostics() { | ||
455 | let mut config = DiagnosticsConfig::default(); | ||
456 | config.disabled.insert("unresolved-module".into()); | ||
457 | |||
458 | let (analysis, file_id) = fixture::file(r#"mod foo;"#); | ||
459 | |||
460 | let diagnostics = | ||
461 | analysis.diagnostics(&config, AssistResolveStrategy::All, file_id).unwrap(); | ||
462 | assert!(diagnostics.is_empty()); | ||
463 | |||
464 | let diagnostics = analysis | ||
465 | .diagnostics(&DiagnosticsConfig::default(), AssistResolveStrategy::All, file_id) | ||
466 | .unwrap(); | ||
467 | assert!(!diagnostics.is_empty()); | ||
468 | } | ||
469 | |||
470 | #[test] | ||
471 | fn import_extern_crate_clash_with_inner_item() { | ||
472 | // This is more of a resolver test, but doesn't really work with the hir_def testsuite. | ||
473 | |||
474 | check_diagnostics( | ||
475 | r#" | ||
476 | //- /lib.rs crate:lib deps:jwt | ||
477 | mod permissions; | ||
478 | |||
479 | use permissions::jwt; | ||
480 | |||
481 | fn f() { | ||
482 | fn inner() {} | ||
483 | jwt::Claims {}; // should resolve to the local one with 0 fields, and not get a diagnostic | ||
484 | } | ||
485 | |||
486 | //- /permissions.rs | ||
487 | pub mod jwt { | ||
488 | pub struct Claims {} | ||
489 | } | ||
490 | |||
491 | //- /jwt/lib.rs crate:jwt | ||
492 | pub struct Claims { | ||
493 | field: u8, | ||
494 | } | ||
495 | "#, | ||
496 | ); | ||
497 | } | ||
498 | } | ||
diff --git a/crates/ide/src/display/navigation_target.rs b/crates/ide/src/display/navigation_target.rs index b75ec411c..455b32456 100644 --- a/crates/ide/src/display/navigation_target.rs +++ b/crates/ide/src/display/navigation_target.rs | |||
@@ -442,10 +442,10 @@ impl TryToNav for hir::TypeParam { | |||
442 | fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> { | 442 | fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> { |
443 | let src = self.source(db)?; | 443 | let src = self.source(db)?; |
444 | let full_range = match &src.value { | 444 | let full_range = match &src.value { |
445 | Either::Left(it) => it | 445 | Either::Left(type_param) => type_param.syntax().text_range(), |
446 | Either::Right(trait_) => trait_ | ||
446 | .name() | 447 | .name() |
447 | .map_or_else(|| it.syntax().text_range(), |name| name.syntax().text_range()), | 448 | .map_or_else(|| trait_.syntax().text_range(), |name| name.syntax().text_range()), |
448 | Either::Right(it) => it.syntax().text_range(), | ||
449 | }; | 449 | }; |
450 | let focus_range = match &src.value { | 450 | let focus_range = match &src.value { |
451 | Either::Left(it) => it.name(), | 451 | Either::Left(it) => it.name(), |
diff --git a/crates/ide/src/doc_links.rs b/crates/ide/src/doc_links.rs index 57ae9455b..7ac0118fe 100644 --- a/crates/ide/src/doc_links.rs +++ b/crates/ide/src/doc_links.rs | |||
@@ -241,6 +241,10 @@ fn get_doc_link(db: &RootDatabase, definition: Definition) -> Option<String> { | |||
241 | Definition::ModuleDef(ModuleDef::Module(module)) => module.krate(), | 241 | Definition::ModuleDef(ModuleDef::Module(module)) => module.krate(), |
242 | _ => definition.module(db)?.krate(), | 242 | _ => definition.module(db)?.krate(), |
243 | }; | 243 | }; |
244 | // FIXME: using import map doesn't make sense here. What we want here is | ||
245 | // canonical path. What import map returns is the shortest path suitable for | ||
246 | // import. See this test: | ||
247 | cov_mark::hit!(test_reexport_order); | ||
244 | let import_map = db.import_map(krate.into()); | 248 | let import_map = db.import_map(krate.into()); |
245 | 249 | ||
246 | let mut base = krate.display_name(db)?.to_string(); | 250 | let mut base = krate.display_name(db)?.to_string(); |
@@ -642,13 +646,15 @@ pub mod foo { | |||
642 | ) | 646 | ) |
643 | } | 647 | } |
644 | 648 | ||
645 | // FIXME: ImportMap will return re-export paths instead of public module | ||
646 | // paths. The correct path to documentation will never be a re-export. | ||
647 | // This problem stops us from resolving stdlib items included in the prelude | ||
648 | // such as `Option::Some` correctly. | ||
649 | #[ignore = "ImportMap may return re-exports"] | ||
650 | #[test] | 649 | #[test] |
651 | fn test_reexport_order() { | 650 | fn test_reexport_order() { |
651 | cov_mark::check!(test_reexport_order); | ||
652 | // FIXME: This should return | ||
653 | // | ||
654 | // https://docs.rs/test/*/test/wrapper/modulestruct.Item.html | ||
655 | // | ||
656 | // That is, we should point inside the module, rather than at the | ||
657 | // re-export. | ||
652 | check( | 658 | check( |
653 | r#" | 659 | r#" |
654 | pub mod wrapper { | 660 | pub mod wrapper { |
@@ -663,7 +669,7 @@ fn foo() { | |||
663 | let bar: wrapper::It$0em; | 669 | let bar: wrapper::It$0em; |
664 | } | 670 | } |
665 | "#, | 671 | "#, |
666 | expect![[r#"https://docs.rs/test/*/test/wrapper/module/struct.Item.html"#]], | 672 | expect![[r#"https://docs.rs/test/*/test/wrapper/struct.Item.html"#]], |
667 | ) | 673 | ) |
668 | } | 674 | } |
669 | } | 675 | } |
diff --git a/crates/ide/src/fixture.rs b/crates/ide/src/fixture.rs index 38e2e866b..cf679edd3 100644 --- a/crates/ide/src/fixture.rs +++ b/crates/ide/src/fixture.rs | |||
@@ -12,14 +12,6 @@ pub(crate) fn file(ra_fixture: &str) -> (Analysis, FileId) { | |||
12 | (host.analysis(), change_fixture.files[0]) | 12 | (host.analysis(), change_fixture.files[0]) |
13 | } | 13 | } |
14 | 14 | ||
15 | /// Creates analysis for many files. | ||
16 | pub(crate) fn files(ra_fixture: &str) -> (Analysis, Vec<FileId>) { | ||
17 | let mut host = AnalysisHost::default(); | ||
18 | let change_fixture = ChangeFixture::parse(ra_fixture); | ||
19 | host.db.apply_change(change_fixture.change); | ||
20 | (host.analysis(), change_fixture.files) | ||
21 | } | ||
22 | |||
23 | /// Creates analysis from a multi-file fixture, returns positions marked with $0. | 15 | /// Creates analysis from a multi-file fixture, returns positions marked with $0. |
24 | pub(crate) fn position(ra_fixture: &str) -> (Analysis, FilePosition) { | 16 | pub(crate) fn position(ra_fixture: &str) -> (Analysis, FilePosition) { |
25 | let mut host = AnalysisHost::default(); | 17 | let mut host = AnalysisHost::default(); |
diff --git a/crates/ide/src/goto_definition.rs b/crates/ide/src/goto_definition.rs index 8dd643a0f..d8e0dc4d5 100644 --- a/crates/ide/src/goto_definition.rs +++ b/crates/ide/src/goto_definition.rs | |||
@@ -1130,15 +1130,15 @@ fn foo<'foobar>(_: &'foobar ()) { | |||
1130 | } | 1130 | } |
1131 | 1131 | ||
1132 | #[test] | 1132 | #[test] |
1133 | #[ignore] // requires the HIR to somehow track these hrtb lifetimes | ||
1134 | fn goto_lifetime_hrtb() { | 1133 | fn goto_lifetime_hrtb() { |
1135 | check( | 1134 | // FIXME: requires the HIR to somehow track these hrtb lifetimes |
1135 | check_unresolved( | ||
1136 | r#"trait Foo<T> {} | 1136 | r#"trait Foo<T> {} |
1137 | fn foo<T>() where for<'a> T: Foo<&'a$0 (u8, u16)>, {} | 1137 | fn foo<T>() where for<'a> T: Foo<&'a$0 (u8, u16)>, {} |
1138 | //^^ | 1138 | //^^ |
1139 | "#, | 1139 | "#, |
1140 | ); | 1140 | ); |
1141 | check( | 1141 | check_unresolved( |
1142 | r#"trait Foo<T> {} | 1142 | r#"trait Foo<T> {} |
1143 | fn foo<T>() where for<'a$0> T: Foo<&'a (u8, u16)>, {} | 1143 | fn foo<T>() where for<'a$0> T: Foo<&'a (u8, u16)>, {} |
1144 | //^^ | 1144 | //^^ |
@@ -1147,9 +1147,9 @@ fn foo<T>() where for<'a$0> T: Foo<&'a (u8, u16)>, {} | |||
1147 | } | 1147 | } |
1148 | 1148 | ||
1149 | #[test] | 1149 | #[test] |
1150 | #[ignore] // requires ForTypes to be implemented | ||
1151 | fn goto_lifetime_hrtb_for_type() { | 1150 | fn goto_lifetime_hrtb_for_type() { |
1152 | check( | 1151 | // FIXME: requires ForTypes to be implemented |
1152 | check_unresolved( | ||
1153 | r#"trait Foo<T> {} | 1153 | r#"trait Foo<T> {} |
1154 | fn foo<T>() where T: for<'a> Foo<&'a$0 (u8, u16)>, {} | 1154 | fn foo<T>() where T: for<'a> Foo<&'a$0 (u8, u16)>, {} |
1155 | //^^ | 1155 | //^^ |
diff --git a/crates/ide/src/goto_type_definition.rs b/crates/ide/src/goto_type_definition.rs index 004d9cb68..ca3c02bf6 100644 --- a/crates/ide/src/goto_type_definition.rs +++ b/crates/ide/src/goto_type_definition.rs | |||
@@ -25,7 +25,7 @@ pub(crate) fn goto_type_definition( | |||
25 | let token: SyntaxToken = pick_best(file.syntax().token_at_offset(position.offset))?; | 25 | let token: SyntaxToken = pick_best(file.syntax().token_at_offset(position.offset))?; |
26 | let token: SyntaxToken = sema.descend_into_macros(token); | 26 | let token: SyntaxToken = sema.descend_into_macros(token); |
27 | 27 | ||
28 | let (ty, node) = sema.token_ancestors_with_macros(token).find_map(|node| { | 28 | let (ty, node) = sema.token_ancestors_with_macros(token.clone()).find_map(|node| { |
29 | let ty = match_ast! { | 29 | let ty = match_ast! { |
30 | match node { | 30 | match node { |
31 | ast::Expr(it) => sema.type_of_expr(&it)?, | 31 | ast::Expr(it) => sema.type_of_expr(&it)?, |
@@ -33,13 +33,23 @@ pub(crate) fn goto_type_definition( | |||
33 | ast::SelfParam(it) => sema.type_of_self(&it)?, | 33 | ast::SelfParam(it) => sema.type_of_self(&it)?, |
34 | ast::Type(it) => sema.resolve_type(&it)?, | 34 | ast::Type(it) => sema.resolve_type(&it)?, |
35 | ast::RecordField(it) => sema.to_def(&it).map(|d| d.ty(db.upcast()))?, | 35 | ast::RecordField(it) => sema.to_def(&it).map(|d| d.ty(db.upcast()))?, |
36 | ast::RecordField(it) => sema.to_def(&it).map(|d| d.ty(db.upcast()))?, | ||
37 | // can't match on RecordExprField directly as `ast::Expr` will match an iteration too early otherwise | ||
38 | ast::NameRef(it) => { | ||
39 | if let Some(record_field) = ast::RecordExprField::for_name_ref(&it) { | ||
40 | let (_, _, ty) = sema.resolve_record_field(&record_field)?; | ||
41 | ty | ||
42 | } else { | ||
43 | let record_field = ast::RecordPatField::for_field_name_ref(&it)?; | ||
44 | sema.resolve_record_pat_field(&record_field)?.ty(db) | ||
45 | } | ||
46 | }, | ||
36 | _ => return None, | 47 | _ => return None, |
37 | } | 48 | } |
38 | }; | 49 | }; |
39 | 50 | ||
40 | Some((ty, node)) | 51 | Some((ty, node)) |
41 | })?; | 52 | })?; |
42 | |||
43 | let adt_def = ty.autoderef(db).filter_map(|ty| ty.as_adt()).last()?; | 53 | let adt_def = ty.autoderef(db).filter_map(|ty| ty.as_adt()).last()?; |
44 | 54 | ||
45 | let nav = adt_def.try_to_nav(db)?; | 55 | let nav = adt_def.try_to_nav(db)?; |
@@ -88,6 +98,54 @@ fn foo() { | |||
88 | } | 98 | } |
89 | 99 | ||
90 | #[test] | 100 | #[test] |
101 | fn goto_type_definition_record_expr_field() { | ||
102 | check( | ||
103 | r#" | ||
104 | struct Bar; | ||
105 | // ^^^ | ||
106 | struct Foo { foo: Bar } | ||
107 | fn foo() { | ||
108 | Foo { foo$0 } | ||
109 | } | ||
110 | "#, | ||
111 | ); | ||
112 | check( | ||
113 | r#" | ||
114 | struct Bar; | ||
115 | // ^^^ | ||
116 | struct Foo { foo: Bar } | ||
117 | fn foo() { | ||
118 | Foo { foo$0: Bar } | ||
119 | } | ||
120 | "#, | ||
121 | ); | ||
122 | } | ||
123 | |||
124 | #[test] | ||
125 | fn goto_type_definition_record_pat_field() { | ||
126 | check( | ||
127 | r#" | ||
128 | struct Bar; | ||
129 | // ^^^ | ||
130 | struct Foo { foo: Bar } | ||
131 | fn foo() { | ||
132 | let Foo { foo$0 }; | ||
133 | } | ||
134 | "#, | ||
135 | ); | ||
136 | check( | ||
137 | r#" | ||
138 | struct Bar; | ||
139 | // ^^^ | ||
140 | struct Foo { foo: Bar } | ||
141 | fn foo() { | ||
142 | let Foo { foo$0: bar }; | ||
143 | } | ||
144 | "#, | ||
145 | ); | ||
146 | } | ||
147 | |||
148 | #[test] | ||
91 | fn goto_type_definition_works_simple_ref() { | 149 | fn goto_type_definition_works_simple_ref() { |
92 | check( | 150 | check( |
93 | r#" | 151 | r#" |
diff --git a/crates/ide/src/hover.rs b/crates/ide/src/hover.rs index c08516805..14cf94d60 100644 --- a/crates/ide/src/hover.rs +++ b/crates/ide/src/hover.rs | |||
@@ -1821,9 +1821,10 @@ pub struct B$0ar | |||
1821 | ); | 1821 | ); |
1822 | } | 1822 | } |
1823 | 1823 | ||
1824 | #[ignore = "path based links currently only support documentation on ModuleDef items"] | ||
1825 | #[test] | 1824 | #[test] |
1826 | fn test_hover_path_link_field() { | 1825 | fn test_hover_path_link_field() { |
1826 | // FIXME: Should be | ||
1827 | // [Foo](https://docs.rs/test/*/test/struct.Foo.html) | ||
1827 | check( | 1828 | check( |
1828 | r#" | 1829 | r#" |
1829 | pub struct Foo; | 1830 | pub struct Foo; |
@@ -1845,7 +1846,7 @@ pub struct Bar { | |||
1845 | 1846 | ||
1846 | --- | 1847 | --- |
1847 | 1848 | ||
1848 | [Foo](https://docs.rs/test/*/test/struct.Foo.html) | 1849 | [Foo](struct.Foo.html) |
1849 | "#]], | 1850 | "#]], |
1850 | ); | 1851 | ); |
1851 | } | 1852 | } |
@@ -2999,29 +3000,24 @@ fn foo(ar$0g: &impl Foo + Bar<S>) {} | |||
2999 | fn test_hover_async_block_impl_trait_has_goto_type_action() { | 3000 | fn test_hover_async_block_impl_trait_has_goto_type_action() { |
3000 | check_actions( | 3001 | check_actions( |
3001 | r#" | 3002 | r#" |
3003 | //- minicore: future | ||
3002 | struct S; | 3004 | struct S; |
3003 | fn foo() { | 3005 | fn foo() { |
3004 | let fo$0o = async { S }; | 3006 | let fo$0o = async { S }; |
3005 | } | 3007 | } |
3006 | |||
3007 | #[prelude_import] use future::*; | ||
3008 | mod future { | ||
3009 | #[lang = "future_trait"] | ||
3010 | pub trait Future { type Output; } | ||
3011 | } | ||
3012 | "#, | 3008 | "#, |
3013 | expect![[r#" | 3009 | expect![[r#" |
3014 | [ | 3010 | [ |
3015 | GoToType( | 3011 | GoToType( |
3016 | [ | 3012 | [ |
3017 | HoverGotoTypeData { | 3013 | HoverGotoTypeData { |
3018 | mod_path: "test::future::Future", | 3014 | mod_path: "core::future::Future", |
3019 | nav: NavigationTarget { | 3015 | nav: NavigationTarget { |
3020 | file_id: FileId( | 3016 | file_id: FileId( |
3021 | 0, | 3017 | 1, |
3022 | ), | 3018 | ), |
3023 | full_range: 101..163, | 3019 | full_range: 244..426, |
3024 | focus_range: 140..146, | 3020 | focus_range: 283..289, |
3025 | name: "Future", | 3021 | name: "Future", |
3026 | kind: Trait, | 3022 | kind: Trait, |
3027 | description: "pub trait Future", | 3023 | description: "pub trait Future", |
diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs index 0511efae3..4bd073cc3 100644 --- a/crates/ide/src/lib.rs +++ b/crates/ide/src/lib.rs | |||
@@ -24,7 +24,6 @@ mod display; | |||
24 | 24 | ||
25 | mod annotations; | 25 | mod annotations; |
26 | mod call_hierarchy; | 26 | mod call_hierarchy; |
27 | mod diagnostics; | ||
28 | mod expand_macro; | 27 | mod expand_macro; |
29 | mod extend_selection; | 28 | mod extend_selection; |
30 | mod file_structure; | 29 | mod file_structure; |
@@ -40,6 +39,7 @@ mod matching_brace; | |||
40 | mod move_item; | 39 | mod move_item; |
41 | mod parent_module; | 40 | mod parent_module; |
42 | mod references; | 41 | mod references; |
42 | mod rename; | ||
43 | mod fn_references; | 43 | mod fn_references; |
44 | mod runnables; | 44 | mod runnables; |
45 | mod ssr; | 45 | mod ssr; |
@@ -71,7 +71,6 @@ use crate::display::ToNav; | |||
71 | pub use crate::{ | 71 | pub use crate::{ |
72 | annotations::{Annotation, AnnotationConfig, AnnotationKind}, | 72 | annotations::{Annotation, AnnotationConfig, AnnotationKind}, |
73 | call_hierarchy::CallItem, | 73 | call_hierarchy::CallItem, |
74 | diagnostics::{Diagnostic, DiagnosticsConfig, Severity}, | ||
75 | display::navigation_target::NavigationTarget, | 74 | display::navigation_target::NavigationTarget, |
76 | expand_macro::ExpandedMacro, | 75 | expand_macro::ExpandedMacro, |
77 | file_structure::{StructureNode, StructureNodeKind}, | 76 | file_structure::{StructureNode, StructureNodeKind}, |
@@ -81,7 +80,8 @@ pub use crate::{ | |||
81 | markup::Markup, | 80 | markup::Markup, |
82 | move_item::Direction, | 81 | move_item::Direction, |
83 | prime_caches::PrimeCachesProgress, | 82 | prime_caches::PrimeCachesProgress, |
84 | references::{rename::RenameError, ReferenceSearchResult}, | 83 | references::ReferenceSearchResult, |
84 | rename::RenameError, | ||
85 | runnables::{Runnable, RunnableKind, TestId}, | 85 | runnables::{Runnable, RunnableKind, TestId}, |
86 | syntax_highlighting::{ | 86 | syntax_highlighting::{ |
87 | tags::{Highlight, HlMod, HlMods, HlOperator, HlPunct, HlTag}, | 87 | tags::{Highlight, HlMod, HlMods, HlOperator, HlPunct, HlTag}, |
@@ -109,6 +109,7 @@ pub use ide_db::{ | |||
109 | symbol_index::Query, | 109 | symbol_index::Query, |
110 | RootDatabase, SymbolKind, | 110 | RootDatabase, SymbolKind, |
111 | }; | 111 | }; |
112 | pub use ide_diagnostics::{Diagnostic, DiagnosticsConfig, Severity}; | ||
112 | pub use ide_ssr::SsrError; | 113 | pub use ide_ssr::SsrError; |
113 | pub use syntax::{TextRange, TextSize}; | 114 | pub use syntax::{TextRange, TextSize}; |
114 | pub use text_edit::{Indel, TextEdit}; | 115 | pub use text_edit::{Indel, TextEdit}; |
@@ -536,7 +537,7 @@ impl Analysis { | |||
536 | ) -> Cancellable<Vec<Assist>> { | 537 | ) -> Cancellable<Vec<Assist>> { |
537 | self.with_db(|db| { | 538 | self.with_db(|db| { |
538 | let ssr_assists = ssr::ssr_assists(db, &resolve, frange); | 539 | let ssr_assists = ssr::ssr_assists(db, &resolve, frange); |
539 | let mut acc = Assist::get(db, config, resolve, frange); | 540 | let mut acc = ide_assists::assists(db, config, resolve, frange); |
540 | acc.extend(ssr_assists.into_iter()); | 541 | acc.extend(ssr_assists.into_iter()); |
541 | acc | 542 | acc |
542 | }) | 543 | }) |
@@ -549,7 +550,7 @@ impl Analysis { | |||
549 | resolve: AssistResolveStrategy, | 550 | resolve: AssistResolveStrategy, |
550 | file_id: FileId, | 551 | file_id: FileId, |
551 | ) -> Cancellable<Vec<Diagnostic>> { | 552 | ) -> Cancellable<Vec<Diagnostic>> { |
552 | self.with_db(|db| diagnostics::diagnostics(db, config, &resolve, file_id)) | 553 | self.with_db(|db| ide_diagnostics::diagnostics(db, config, &resolve, file_id)) |
553 | } | 554 | } |
554 | 555 | ||
555 | /// Convenience function to return assists + quick fixes for diagnostics | 556 | /// Convenience function to return assists + quick fixes for diagnostics |
@@ -566,9 +567,8 @@ impl Analysis { | |||
566 | }; | 567 | }; |
567 | 568 | ||
568 | self.with_db(|db| { | 569 | self.with_db(|db| { |
569 | let ssr_assists = ssr::ssr_assists(db, &resolve, frange); | ||
570 | let diagnostic_assists = if include_fixes { | 570 | let diagnostic_assists = if include_fixes { |
571 | diagnostics::diagnostics(db, diagnostics_config, &resolve, frange.file_id) | 571 | ide_diagnostics::diagnostics(db, diagnostics_config, &resolve, frange.file_id) |
572 | .into_iter() | 572 | .into_iter() |
573 | .flat_map(|it| it.fixes.unwrap_or_default()) | 573 | .flat_map(|it| it.fixes.unwrap_or_default()) |
574 | .filter(|it| it.target.intersect(frange.range).is_some()) | 574 | .filter(|it| it.target.intersect(frange.range).is_some()) |
@@ -576,10 +576,12 @@ impl Analysis { | |||
576 | } else { | 576 | } else { |
577 | Vec::new() | 577 | Vec::new() |
578 | }; | 578 | }; |
579 | let ssr_assists = ssr::ssr_assists(db, &resolve, frange); | ||
580 | let assists = ide_assists::assists(db, assist_config, resolve, frange); | ||
579 | 581 | ||
580 | let mut res = Assist::get(db, assist_config, resolve, frange); | 582 | let mut res = diagnostic_assists; |
581 | res.extend(ssr_assists.into_iter()); | 583 | res.extend(ssr_assists.into_iter()); |
582 | res.extend(diagnostic_assists.into_iter()); | 584 | res.extend(assists.into_iter()); |
583 | 585 | ||
584 | res | 586 | res |
585 | }) | 587 | }) |
@@ -592,14 +594,14 @@ impl Analysis { | |||
592 | position: FilePosition, | 594 | position: FilePosition, |
593 | new_name: &str, | 595 | new_name: &str, |
594 | ) -> Cancellable<Result<SourceChange, RenameError>> { | 596 | ) -> Cancellable<Result<SourceChange, RenameError>> { |
595 | self.with_db(|db| references::rename::rename(db, position, new_name)) | 597 | self.with_db(|db| rename::rename(db, position, new_name)) |
596 | } | 598 | } |
597 | 599 | ||
598 | pub fn prepare_rename( | 600 | pub fn prepare_rename( |
599 | &self, | 601 | &self, |
600 | position: FilePosition, | 602 | position: FilePosition, |
601 | ) -> Cancellable<Result<RangeInfo<()>, RenameError>> { | 603 | ) -> Cancellable<Result<RangeInfo<()>, RenameError>> { |
602 | self.with_db(|db| references::rename::prepare_rename(db, position)) | 604 | self.with_db(|db| rename::prepare_rename(db, position)) |
603 | } | 605 | } |
604 | 606 | ||
605 | pub fn will_rename_file( | 607 | pub fn will_rename_file( |
@@ -607,7 +609,7 @@ impl Analysis { | |||
607 | file_id: FileId, | 609 | file_id: FileId, |
608 | new_name_stem: &str, | 610 | new_name_stem: &str, |
609 | ) -> Cancellable<Option<SourceChange>> { | 611 | ) -> Cancellable<Option<SourceChange>> { |
610 | self.with_db(|db| references::rename::will_rename_file(db, file_id, new_name_stem)) | 612 | self.with_db(|db| rename::will_rename_file(db, file_id, new_name_stem)) |
611 | } | 613 | } |
612 | 614 | ||
613 | pub fn structural_search_replace( | 615 | pub fn structural_search_replace( |
diff --git a/crates/ide/src/references.rs b/crates/ide/src/references.rs index a0fdead2c..945c9b9e1 100644 --- a/crates/ide/src/references.rs +++ b/crates/ide/src/references.rs | |||
@@ -9,8 +9,6 @@ | |||
9 | //! at the index that the match starts at and its tree parent is | 9 | //! at the index that the match starts at and its tree parent is |
10 | //! resolved to the search element definition, we get a reference. | 10 | //! resolved to the search element definition, we get a reference. |
11 | 11 | ||
12 | pub(crate) mod rename; | ||
13 | |||
14 | use hir::{PathResolution, Semantics}; | 12 | use hir::{PathResolution, Semantics}; |
15 | use ide_db::{ | 13 | use ide_db::{ |
16 | base_db::FileId, | 14 | base_db::FileId, |
diff --git a/crates/ide/src/references/rename.rs b/crates/ide/src/rename.rs index 6b3d02bf4..8096dfa0e 100644 --- a/crates/ide/src/references/rename.rs +++ b/crates/ide/src/rename.rs | |||
@@ -1,45 +1,25 @@ | |||
1 | //! Renaming functionality | 1 | //! Renaming functionality. |
2 | //! | 2 | //! |
3 | //! All reference and file rename requests go through here where the corresponding [`SourceChange`]s | 3 | //! This is mostly front-end for [`ide_db::rename`], but it also includes the |
4 | //! will be calculated. | 4 | //! tests. This module also implements a couple of magic tricks, like renaming |
5 | use std::fmt::{self, Display}; | 5 | //! `self` and to `self` (to switch between associated function and method). |
6 | 6 | use hir::{AsAssocItem, InFile, Semantics}; | |
7 | use either::Either; | ||
8 | use hir::{AsAssocItem, FieldSource, HasSource, InFile, ModuleSource, Semantics}; | ||
9 | use ide_db::{ | 7 | use ide_db::{ |
10 | base_db::{AnchoredPathBuf, FileId, FileRange}, | 8 | base_db::FileId, |
11 | defs::{Definition, NameClass, NameRefClass}, | 9 | defs::{Definition, NameClass, NameRefClass}, |
12 | search::FileReference, | 10 | rename::{bail, format_err, source_edit_from_references, IdentifierKind}, |
13 | RootDatabase, | 11 | RootDatabase, |
14 | }; | 12 | }; |
15 | use stdx::never; | 13 | use stdx::never; |
16 | use syntax::{ | 14 | use syntax::{ast, AstNode, SyntaxNode}; |
17 | ast::{self, NameOwner}, | ||
18 | lex_single_syntax_kind, AstNode, SyntaxKind, SyntaxNode, T, | ||
19 | }; | ||
20 | 15 | ||
21 | use text_edit::TextEdit; | 16 | use text_edit::TextEdit; |
22 | 17 | ||
23 | use crate::{FilePosition, FileSystemEdit, RangeInfo, SourceChange, TextRange}; | 18 | use crate::{FilePosition, RangeInfo, SourceChange}; |
24 | |||
25 | type RenameResult<T> = Result<T, RenameError>; | ||
26 | #[derive(Debug)] | ||
27 | pub struct RenameError(String); | ||
28 | |||
29 | impl fmt::Display for RenameError { | ||
30 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||
31 | Display::fmt(&self.0, f) | ||
32 | } | ||
33 | } | ||
34 | 19 | ||
35 | macro_rules! format_err { | 20 | pub use ide_db::rename::RenameError; |
36 | ($fmt:expr) => {RenameError(format!($fmt))}; | ||
37 | ($fmt:expr, $($arg:tt)+) => {RenameError(format!($fmt, $($arg)+))} | ||
38 | } | ||
39 | 21 | ||
40 | macro_rules! bail { | 22 | type RenameResult<T> = Result<T, RenameError>; |
41 | ($($tokens:tt)*) => {return Err(format_err!($($tokens)*))} | ||
42 | } | ||
43 | 23 | ||
44 | /// Prepares a rename. The sole job of this function is to return the TextRange of the thing that is | 24 | /// Prepares a rename. The sole job of this function is to return the TextRange of the thing that is |
45 | /// being targeted for a rename. | 25 | /// being targeted for a rename. |
@@ -52,7 +32,8 @@ pub(crate) fn prepare_rename( | |||
52 | let syntax = source_file.syntax(); | 32 | let syntax = source_file.syntax(); |
53 | 33 | ||
54 | let def = find_definition(&sema, syntax, position)?; | 34 | let def = find_definition(&sema, syntax, position)?; |
55 | let frange = def_name_range(&&sema, def) | 35 | let frange = def |
36 | .range_for_rename(&sema) | ||
56 | .ok_or_else(|| format_err!("No references found at position"))?; | 37 | .ok_or_else(|| format_err!("No references found at position"))?; |
57 | Ok(RangeInfo::new(frange.range, ())) | 38 | Ok(RangeInfo::new(frange.range, ())) |
58 | } | 39 | } |
@@ -98,14 +79,7 @@ pub(crate) fn rename_with_semantics( | |||
98 | } | 79 | } |
99 | } | 80 | } |
100 | 81 | ||
101 | match def { | 82 | def.rename(sema, new_name) |
102 | Definition::ModuleDef(hir::ModuleDef::Module(module)) => rename_mod(sema, module, new_name), | ||
103 | Definition::SelfType(_) => bail!("Cannot rename `Self`"), | ||
104 | Definition::ModuleDef(hir::ModuleDef::BuiltinType(_)) => { | ||
105 | bail!("Cannot rename builtin type") | ||
106 | } | ||
107 | def => rename_reference(sema, def, new_name), | ||
108 | } | ||
109 | } | 83 | } |
110 | 84 | ||
111 | /// Called by the client when it is about to rename a file. | 85 | /// Called by the client when it is about to rename a file. |
@@ -116,38 +90,12 @@ pub(crate) fn will_rename_file( | |||
116 | ) -> Option<SourceChange> { | 90 | ) -> Option<SourceChange> { |
117 | let sema = Semantics::new(db); | 91 | let sema = Semantics::new(db); |
118 | let module = sema.to_module_def(file_id)?; | 92 | let module = sema.to_module_def(file_id)?; |
119 | let mut change = rename_mod(&sema, module, new_name_stem).ok()?; | 93 | let def = Definition::ModuleDef(module.into()); |
94 | let mut change = def.rename(&sema, new_name_stem).ok()?; | ||
120 | change.file_system_edits.clear(); | 95 | change.file_system_edits.clear(); |
121 | Some(change) | 96 | Some(change) |
122 | } | 97 | } |
123 | 98 | ||
124 | #[derive(Copy, Clone, Debug, PartialEq)] | ||
125 | enum IdentifierKind { | ||
126 | Ident, | ||
127 | Lifetime, | ||
128 | Underscore, | ||
129 | } | ||
130 | |||
131 | impl IdentifierKind { | ||
132 | fn classify(new_name: &str) -> RenameResult<IdentifierKind> { | ||
133 | match lex_single_syntax_kind(new_name) { | ||
134 | Some(res) => match res { | ||
135 | (SyntaxKind::IDENT, _) => Ok(IdentifierKind::Ident), | ||
136 | (T![_], _) => Ok(IdentifierKind::Underscore), | ||
137 | (SyntaxKind::LIFETIME_IDENT, _) if new_name != "'static" && new_name != "'_" => { | ||
138 | Ok(IdentifierKind::Lifetime) | ||
139 | } | ||
140 | (SyntaxKind::LIFETIME_IDENT, _) => { | ||
141 | bail!("Invalid name `{}`: not a lifetime identifier", new_name) | ||
142 | } | ||
143 | (_, Some(syntax_error)) => bail!("Invalid name `{}`: {}", new_name, syntax_error), | ||
144 | (_, None) => bail!("Invalid name `{}`: not an identifier", new_name), | ||
145 | }, | ||
146 | None => bail!("Invalid name `{}`: not an identifier", new_name), | ||
147 | } | ||
148 | } | ||
149 | } | ||
150 | |||
151 | fn find_definition( | 99 | fn find_definition( |
152 | sema: &Semantics<RootDatabase>, | 100 | sema: &Semantics<RootDatabase>, |
153 | syntax: &SyntaxNode, | 101 | syntax: &SyntaxNode, |
@@ -189,126 +137,6 @@ fn find_definition( | |||
189 | .ok_or_else(|| format_err!("No references found at position")) | 137 | .ok_or_else(|| format_err!("No references found at position")) |
190 | } | 138 | } |
191 | 139 | ||
192 | fn rename_mod( | ||
193 | sema: &Semantics<RootDatabase>, | ||
194 | module: hir::Module, | ||
195 | new_name: &str, | ||
196 | ) -> RenameResult<SourceChange> { | ||
197 | if IdentifierKind::classify(new_name)? != IdentifierKind::Ident { | ||
198 | bail!("Invalid name `{0}`: cannot rename module to {0}", new_name); | ||
199 | } | ||
200 | |||
201 | let mut source_change = SourceChange::default(); | ||
202 | |||
203 | let InFile { file_id, value: def_source } = module.definition_source(sema.db); | ||
204 | let file_id = file_id.original_file(sema.db); | ||
205 | if let ModuleSource::SourceFile(..) = def_source { | ||
206 | // mod is defined in path/to/dir/mod.rs | ||
207 | let path = if module.is_mod_rs(sema.db) { | ||
208 | format!("../{}/mod.rs", new_name) | ||
209 | } else { | ||
210 | format!("{}.rs", new_name) | ||
211 | }; | ||
212 | let dst = AnchoredPathBuf { anchor: file_id, path }; | ||
213 | let move_file = FileSystemEdit::MoveFile { src: file_id, dst }; | ||
214 | source_change.push_file_system_edit(move_file); | ||
215 | } | ||
216 | |||
217 | if let Some(InFile { file_id, value: decl_source }) = module.declaration_source(sema.db) { | ||
218 | let file_id = file_id.original_file(sema.db); | ||
219 | match decl_source.name() { | ||
220 | Some(name) => source_change.insert_source_edit( | ||
221 | file_id, | ||
222 | TextEdit::replace(name.syntax().text_range(), new_name.to_string()), | ||
223 | ), | ||
224 | _ => never!("Module source node is missing a name"), | ||
225 | } | ||
226 | } | ||
227 | let def = Definition::ModuleDef(hir::ModuleDef::Module(module)); | ||
228 | let usages = def.usages(sema).all(); | ||
229 | let ref_edits = usages.iter().map(|(&file_id, references)| { | ||
230 | (file_id, source_edit_from_references(references, def, new_name)) | ||
231 | }); | ||
232 | source_change.extend(ref_edits); | ||
233 | |||
234 | Ok(source_change) | ||
235 | } | ||
236 | |||
237 | fn rename_reference( | ||
238 | sema: &Semantics<RootDatabase>, | ||
239 | mut def: Definition, | ||
240 | new_name: &str, | ||
241 | ) -> RenameResult<SourceChange> { | ||
242 | let ident_kind = IdentifierKind::classify(new_name)?; | ||
243 | |||
244 | if matches!( | ||
245 | def, // is target a lifetime? | ||
246 | Definition::GenericParam(hir::GenericParam::LifetimeParam(_)) | Definition::Label(_) | ||
247 | ) { | ||
248 | match ident_kind { | ||
249 | IdentifierKind::Ident | IdentifierKind::Underscore => { | ||
250 | cov_mark::hit!(rename_not_a_lifetime_ident_ref); | ||
251 | bail!("Invalid name `{}`: not a lifetime identifier", new_name); | ||
252 | } | ||
253 | IdentifierKind::Lifetime => cov_mark::hit!(rename_lifetime), | ||
254 | } | ||
255 | } else { | ||
256 | match (ident_kind, def) { | ||
257 | (IdentifierKind::Lifetime, _) => { | ||
258 | cov_mark::hit!(rename_not_an_ident_ref); | ||
259 | bail!("Invalid name `{}`: not an identifier", new_name); | ||
260 | } | ||
261 | (IdentifierKind::Ident, _) => cov_mark::hit!(rename_non_local), | ||
262 | (IdentifierKind::Underscore, _) => (), | ||
263 | } | ||
264 | } | ||
265 | |||
266 | def = match def { | ||
267 | // HACK: resolve trait impl items to the item def of the trait definition | ||
268 | // so that we properly resolve all trait item references | ||
269 | Definition::ModuleDef(mod_def) => mod_def | ||
270 | .as_assoc_item(sema.db) | ||
271 | .and_then(|it| it.containing_trait_impl(sema.db)) | ||
272 | .and_then(|it| { | ||
273 | it.items(sema.db).into_iter().find_map(|it| match (it, mod_def) { | ||
274 | (hir::AssocItem::Function(trait_func), hir::ModuleDef::Function(func)) | ||
275 | if trait_func.name(sema.db) == func.name(sema.db) => | ||
276 | { | ||
277 | Some(Definition::ModuleDef(hir::ModuleDef::Function(trait_func))) | ||
278 | } | ||
279 | (hir::AssocItem::Const(trait_konst), hir::ModuleDef::Const(konst)) | ||
280 | if trait_konst.name(sema.db) == konst.name(sema.db) => | ||
281 | { | ||
282 | Some(Definition::ModuleDef(hir::ModuleDef::Const(trait_konst))) | ||
283 | } | ||
284 | ( | ||
285 | hir::AssocItem::TypeAlias(trait_type_alias), | ||
286 | hir::ModuleDef::TypeAlias(type_alias), | ||
287 | ) if trait_type_alias.name(sema.db) == type_alias.name(sema.db) => { | ||
288 | Some(Definition::ModuleDef(hir::ModuleDef::TypeAlias(trait_type_alias))) | ||
289 | } | ||
290 | _ => None, | ||
291 | }) | ||
292 | }) | ||
293 | .unwrap_or(def), | ||
294 | _ => def, | ||
295 | }; | ||
296 | let usages = def.usages(sema).all(); | ||
297 | |||
298 | if !usages.is_empty() && ident_kind == IdentifierKind::Underscore { | ||
299 | cov_mark::hit!(rename_underscore_multiple); | ||
300 | bail!("Cannot rename reference to `_` as it is being referenced multiple times"); | ||
301 | } | ||
302 | let mut source_change = SourceChange::default(); | ||
303 | source_change.extend(usages.iter().map(|(&file_id, references)| { | ||
304 | (file_id, source_edit_from_references(references, def, new_name)) | ||
305 | })); | ||
306 | |||
307 | let (file_id, edit) = source_edit_from_def(sema, def, new_name)?; | ||
308 | source_change.insert_source_edit(file_id, edit); | ||
309 | Ok(source_change) | ||
310 | } | ||
311 | |||
312 | fn rename_to_self(sema: &Semantics<RootDatabase>, local: hir::Local) -> RenameResult<SourceChange> { | 140 | fn rename_to_self(sema: &Semantics<RootDatabase>, local: hir::Local) -> RenameResult<SourceChange> { |
313 | if never!(local.is_self(sema.db)) { | 141 | if never!(local.is_self(sema.db)) { |
314 | bail!("rename_to_self invoked on self"); | 142 | bail!("rename_to_self invoked on self"); |
@@ -426,243 +254,6 @@ fn text_edit_from_self_param(self_param: &ast::SelfParam, new_name: &str) -> Opt | |||
426 | Some(TextEdit::replace(self_param.syntax().text_range(), replacement_text)) | 254 | Some(TextEdit::replace(self_param.syntax().text_range(), replacement_text)) |
427 | } | 255 | } |
428 | 256 | ||
429 | fn source_edit_from_references( | ||
430 | references: &[FileReference], | ||
431 | def: Definition, | ||
432 | new_name: &str, | ||
433 | ) -> TextEdit { | ||
434 | let mut edit = TextEdit::builder(); | ||
435 | for reference in references { | ||
436 | let (range, replacement) = match &reference.name { | ||
437 | // if the ranges differ then the node is inside a macro call, we can't really attempt | ||
438 | // to make special rewrites like shorthand syntax and such, so just rename the node in | ||
439 | // the macro input | ||
440 | ast::NameLike::NameRef(name_ref) | ||
441 | if name_ref.syntax().text_range() == reference.range => | ||
442 | { | ||
443 | source_edit_from_name_ref(name_ref, new_name, def) | ||
444 | } | ||
445 | ast::NameLike::Name(name) if name.syntax().text_range() == reference.range => { | ||
446 | source_edit_from_name(name, new_name) | ||
447 | } | ||
448 | _ => None, | ||
449 | } | ||
450 | .unwrap_or_else(|| (reference.range, new_name.to_string())); | ||
451 | edit.replace(range, replacement); | ||
452 | } | ||
453 | edit.finish() | ||
454 | } | ||
455 | |||
456 | fn source_edit_from_name(name: &ast::Name, new_name: &str) -> Option<(TextRange, String)> { | ||
457 | if let Some(_) = ast::RecordPatField::for_field_name(name) { | ||
458 | if let Some(ident_pat) = name.syntax().parent().and_then(ast::IdentPat::cast) { | ||
459 | return Some(( | ||
460 | TextRange::empty(ident_pat.syntax().text_range().start()), | ||
461 | [new_name, ": "].concat(), | ||
462 | )); | ||
463 | } | ||
464 | } | ||
465 | None | ||
466 | } | ||
467 | |||
468 | fn source_edit_from_name_ref( | ||
469 | name_ref: &ast::NameRef, | ||
470 | new_name: &str, | ||
471 | def: Definition, | ||
472 | ) -> Option<(TextRange, String)> { | ||
473 | if let Some(record_field) = ast::RecordExprField::for_name_ref(name_ref) { | ||
474 | let rcf_name_ref = record_field.name_ref(); | ||
475 | let rcf_expr = record_field.expr(); | ||
476 | match (rcf_name_ref, rcf_expr.and_then(|it| it.name_ref())) { | ||
477 | // field: init-expr, check if we can use a field init shorthand | ||
478 | (Some(field_name), Some(init)) => { | ||
479 | if field_name == *name_ref { | ||
480 | if init.text() == new_name { | ||
481 | cov_mark::hit!(test_rename_field_put_init_shorthand); | ||
482 | // same names, we can use a shorthand here instead. | ||
483 | // we do not want to erase attributes hence this range start | ||
484 | let s = field_name.syntax().text_range().start(); | ||
485 | let e = record_field.syntax().text_range().end(); | ||
486 | return Some((TextRange::new(s, e), new_name.to_owned())); | ||
487 | } | ||
488 | } else if init == *name_ref { | ||
489 | if field_name.text() == new_name { | ||
490 | cov_mark::hit!(test_rename_local_put_init_shorthand); | ||
491 | // same names, we can use a shorthand here instead. | ||
492 | // we do not want to erase attributes hence this range start | ||
493 | let s = field_name.syntax().text_range().start(); | ||
494 | let e = record_field.syntax().text_range().end(); | ||
495 | return Some((TextRange::new(s, e), new_name.to_owned())); | ||
496 | } | ||
497 | } | ||
498 | None | ||
499 | } | ||
500 | // init shorthand | ||
501 | // FIXME: instead of splitting the shorthand, recursively trigger a rename of the | ||
502 | // other name https://github.com/rust-analyzer/rust-analyzer/issues/6547 | ||
503 | (None, Some(_)) if matches!(def, Definition::Field(_)) => { | ||
504 | cov_mark::hit!(test_rename_field_in_field_shorthand); | ||
505 | let s = name_ref.syntax().text_range().start(); | ||
506 | Some((TextRange::empty(s), format!("{}: ", new_name))) | ||
507 | } | ||
508 | (None, Some(_)) if matches!(def, Definition::Local(_)) => { | ||
509 | cov_mark::hit!(test_rename_local_in_field_shorthand); | ||
510 | let s = name_ref.syntax().text_range().end(); | ||
511 | Some((TextRange::empty(s), format!(": {}", new_name))) | ||
512 | } | ||
513 | _ => None, | ||
514 | } | ||
515 | } else if let Some(record_field) = ast::RecordPatField::for_field_name_ref(name_ref) { | ||
516 | let rcf_name_ref = record_field.name_ref(); | ||
517 | let rcf_pat = record_field.pat(); | ||
518 | match (rcf_name_ref, rcf_pat) { | ||
519 | // field: rename | ||
520 | (Some(field_name), Some(ast::Pat::IdentPat(pat))) if field_name == *name_ref => { | ||
521 | // field name is being renamed | ||
522 | if pat.name().map_or(false, |it| it.text() == new_name) { | ||
523 | cov_mark::hit!(test_rename_field_put_init_shorthand_pat); | ||
524 | // same names, we can use a shorthand here instead/ | ||
525 | // we do not want to erase attributes hence this range start | ||
526 | let s = field_name.syntax().text_range().start(); | ||
527 | let e = record_field.syntax().text_range().end(); | ||
528 | Some((TextRange::new(s, e), pat.to_string())) | ||
529 | } else { | ||
530 | None | ||
531 | } | ||
532 | } | ||
533 | _ => None, | ||
534 | } | ||
535 | } else { | ||
536 | None | ||
537 | } | ||
538 | } | ||
539 | |||
540 | fn source_edit_from_def( | ||
541 | sema: &Semantics<RootDatabase>, | ||
542 | def: Definition, | ||
543 | new_name: &str, | ||
544 | ) -> RenameResult<(FileId, TextEdit)> { | ||
545 | let frange: FileRange = def_name_range(sema, def) | ||
546 | .ok_or_else(|| format_err!("No identifier available to rename"))?; | ||
547 | |||
548 | let mut replacement_text = String::new(); | ||
549 | let mut repl_range = frange.range; | ||
550 | if let Definition::Local(local) = def { | ||
551 | if let Either::Left(pat) = local.source(sema.db).value { | ||
552 | if matches!( | ||
553 | pat.syntax().parent().and_then(ast::RecordPatField::cast), | ||
554 | Some(pat_field) if pat_field.name_ref().is_none() | ||
555 | ) { | ||
556 | replacement_text.push_str(": "); | ||
557 | replacement_text.push_str(new_name); | ||
558 | repl_range = TextRange::new( | ||
559 | pat.syntax().text_range().end(), | ||
560 | pat.syntax().text_range().end(), | ||
561 | ); | ||
562 | } | ||
563 | } | ||
564 | } | ||
565 | if replacement_text.is_empty() { | ||
566 | replacement_text.push_str(new_name); | ||
567 | } | ||
568 | let edit = TextEdit::replace(repl_range, replacement_text); | ||
569 | Ok((frange.file_id, edit)) | ||
570 | } | ||
571 | |||
572 | fn def_name_range(sema: &Semantics<RootDatabase>, def: Definition) -> Option<FileRange> { | ||
573 | // FIXME: the `original_file_range` calls here are wrong -- they never fail, | ||
574 | // and _fall back_ to the entirety of the macro call. Such fall back is | ||
575 | // incorrect for renames. The safe behavior would be to return an error for | ||
576 | // such cases. The correct behavior would be to return an auxiliary list of | ||
577 | // "can't rename these occurrences in macros" items, and then show some kind | ||
578 | // of a dialog to the user. | ||
579 | |||
580 | let res = match def { | ||
581 | Definition::Macro(mac) => { | ||
582 | let src = mac.source(sema.db)?; | ||
583 | let name = match &src.value { | ||
584 | Either::Left(it) => it.name()?, | ||
585 | Either::Right(it) => it.name()?, | ||
586 | }; | ||
587 | src.with_value(name.syntax()).original_file_range(sema.db) | ||
588 | } | ||
589 | Definition::Field(field) => { | ||
590 | let src = field.source(sema.db)?; | ||
591 | |||
592 | match &src.value { | ||
593 | FieldSource::Named(record_field) => { | ||
594 | let name = record_field.name()?; | ||
595 | src.with_value(name.syntax()).original_file_range(sema.db) | ||
596 | } | ||
597 | FieldSource::Pos(_) => { | ||
598 | return None; | ||
599 | } | ||
600 | } | ||
601 | } | ||
602 | Definition::ModuleDef(module_def) => match module_def { | ||
603 | hir::ModuleDef::Module(module) => { | ||
604 | let src = module.declaration_source(sema.db)?; | ||
605 | let name = src.value.name()?; | ||
606 | src.with_value(name.syntax()).original_file_range(sema.db) | ||
607 | } | ||
608 | hir::ModuleDef::Function(it) => name_range(it, sema)?, | ||
609 | hir::ModuleDef::Adt(adt) => match adt { | ||
610 | hir::Adt::Struct(it) => name_range(it, sema)?, | ||
611 | hir::Adt::Union(it) => name_range(it, sema)?, | ||
612 | hir::Adt::Enum(it) => name_range(it, sema)?, | ||
613 | }, | ||
614 | hir::ModuleDef::Variant(it) => name_range(it, sema)?, | ||
615 | hir::ModuleDef::Const(it) => name_range(it, sema)?, | ||
616 | hir::ModuleDef::Static(it) => name_range(it, sema)?, | ||
617 | hir::ModuleDef::Trait(it) => name_range(it, sema)?, | ||
618 | hir::ModuleDef::TypeAlias(it) => name_range(it, sema)?, | ||
619 | hir::ModuleDef::BuiltinType(_) => return None, | ||
620 | }, | ||
621 | Definition::SelfType(_) => return None, | ||
622 | Definition::Local(local) => { | ||
623 | let src = local.source(sema.db); | ||
624 | let name = match &src.value { | ||
625 | Either::Left(bind_pat) => bind_pat.name()?, | ||
626 | Either::Right(_) => return None, | ||
627 | }; | ||
628 | src.with_value(name.syntax()).original_file_range(sema.db) | ||
629 | } | ||
630 | Definition::GenericParam(generic_param) => match generic_param { | ||
631 | hir::GenericParam::TypeParam(type_param) => { | ||
632 | let src = type_param.source(sema.db)?; | ||
633 | let name = match &src.value { | ||
634 | Either::Left(_) => return None, | ||
635 | Either::Right(type_param) => type_param.name()?, | ||
636 | }; | ||
637 | src.with_value(name.syntax()).original_file_range(sema.db) | ||
638 | } | ||
639 | hir::GenericParam::LifetimeParam(lifetime_param) => { | ||
640 | let src = lifetime_param.source(sema.db)?; | ||
641 | let lifetime = src.value.lifetime()?; | ||
642 | src.with_value(lifetime.syntax()).original_file_range(sema.db) | ||
643 | } | ||
644 | hir::GenericParam::ConstParam(it) => name_range(it, sema)?, | ||
645 | }, | ||
646 | Definition::Label(label) => { | ||
647 | let src = label.source(sema.db); | ||
648 | let lifetime = src.value.lifetime()?; | ||
649 | src.with_value(lifetime.syntax()).original_file_range(sema.db) | ||
650 | } | ||
651 | }; | ||
652 | return Some(res); | ||
653 | |||
654 | fn name_range<D>(def: D, sema: &Semantics<RootDatabase>) -> Option<FileRange> | ||
655 | where | ||
656 | D: HasSource, | ||
657 | D::Ast: ast::NameOwner, | ||
658 | { | ||
659 | let src = def.source(sema.db)?; | ||
660 | let name = src.value.name()?; | ||
661 | let res = src.with_value(name.syntax()).original_file_range(sema.db); | ||
662 | Some(res) | ||
663 | } | ||
664 | } | ||
665 | |||
666 | #[cfg(test)] | 257 | #[cfg(test)] |
667 | mod tests { | 258 | mod tests { |
668 | use expect_test::{expect, Expect}; | 259 | use expect_test::{expect, Expect}; |
@@ -2178,4 +1769,22 @@ fn f() { <()>::BAR$0; }"#, | |||
2178 | res, | 1769 | res, |
2179 | ); | 1770 | ); |
2180 | } | 1771 | } |
1772 | |||
1773 | #[test] | ||
1774 | fn macros_are_broken_lol() { | ||
1775 | cov_mark::check!(macros_are_broken_lol); | ||
1776 | check( | ||
1777 | "lol", | ||
1778 | r#" | ||
1779 | macro_rules! m { () => { fn f() {} } } | ||
1780 | m!(); | ||
1781 | fn main() { f$0() } | ||
1782 | "#, | ||
1783 | r#" | ||
1784 | macro_rules! m { () => { fn f() {} } } | ||
1785 | lol | ||
1786 | fn main() { lol() } | ||
1787 | "#, | ||
1788 | ) | ||
1789 | } | ||
2181 | } | 1790 | } |
diff --git a/crates/ide/src/syntax_highlighting/highlight.rs b/crates/ide/src/syntax_highlighting/highlight.rs index 7a53268e8..6834fe11a 100644 --- a/crates/ide/src/syntax_highlighting/highlight.rs +++ b/crates/ide/src/syntax_highlighting/highlight.rs | |||
@@ -48,7 +48,13 @@ pub(super) fn element( | |||
48 | match name_kind { | 48 | match name_kind { |
49 | Some(NameClass::ExternCrate(_)) => SymbolKind::Module.into(), | 49 | Some(NameClass::ExternCrate(_)) => SymbolKind::Module.into(), |
50 | Some(NameClass::Definition(def)) => { | 50 | Some(NameClass::Definition(def)) => { |
51 | highlight_def(db, krate, def) | HlMod::Definition | 51 | let mut h = highlight_def(db, krate, def) | HlMod::Definition; |
52 | if let Definition::ModuleDef(hir::ModuleDef::Trait(trait_)) = &def { | ||
53 | if trait_.is_unsafe(db) { | ||
54 | h |= HlMod::Unsafe; | ||
55 | } | ||
56 | } | ||
57 | h | ||
52 | } | 58 | } |
53 | Some(NameClass::ConstReference(def)) => highlight_def(db, krate, def), | 59 | Some(NameClass::ConstReference(def)) => highlight_def(db, krate, def), |
54 | Some(NameClass::PatFieldShorthand { field_ref, .. }) => { | 60 | Some(NameClass::PatFieldShorthand { field_ref, .. }) => { |
@@ -87,20 +93,34 @@ pub(super) fn element( | |||
87 | 93 | ||
88 | let mut h = highlight_def(db, krate, def); | 94 | let mut h = highlight_def(db, krate, def); |
89 | 95 | ||
90 | if let Definition::Local(local) = &def { | 96 | match def { |
91 | if is_consumed_lvalue(name_ref.syntax().clone().into(), local, db) { | 97 | Definition::Local(local) |
98 | if is_consumed_lvalue( | ||
99 | name_ref.syntax().clone().into(), | ||
100 | &local, | ||
101 | db, | ||
102 | ) => | ||
103 | { | ||
92 | h |= HlMod::Consuming; | 104 | h |= HlMod::Consuming; |
93 | } | 105 | } |
94 | } | 106 | Definition::ModuleDef(hir::ModuleDef::Trait(trait_)) |
95 | 107 | if trait_.is_unsafe(db) => | |
96 | if let Some(parent) = name_ref.syntax().parent() { | 108 | { |
97 | if matches!(parent.kind(), FIELD_EXPR | RECORD_PAT_FIELD) { | 109 | if ast::Impl::for_trait_name_ref(&name_ref).is_some() { |
98 | if let Definition::Field(field) = def { | 110 | h |= HlMod::Unsafe; |
99 | if let hir::VariantDef::Union(_) = field.parent_def(db) { | 111 | } |
100 | h |= HlMod::Unsafe; | 112 | } |
113 | Definition::Field(field) => { | ||
114 | if let Some(parent) = name_ref.syntax().parent() { | ||
115 | if matches!(parent.kind(), FIELD_EXPR | RECORD_PAT_FIELD) { | ||
116 | if let hir::VariantDef::Union(_) = field.parent_def(db) | ||
117 | { | ||
118 | h |= HlMod::Unsafe; | ||
119 | } | ||
101 | } | 120 | } |
102 | } | 121 | } |
103 | } | 122 | } |
123 | _ => (), | ||
104 | } | 124 | } |
105 | 125 | ||
106 | h | 126 | h |
@@ -354,15 +374,7 @@ fn highlight_def(db: &RootDatabase, krate: Option<hir::Crate>, def: Definition) | |||
354 | 374 | ||
355 | h | 375 | h |
356 | } | 376 | } |
357 | hir::ModuleDef::Trait(trait_) => { | 377 | hir::ModuleDef::Trait(_) => Highlight::new(HlTag::Symbol(SymbolKind::Trait)), |
358 | let mut h = Highlight::new(HlTag::Symbol(SymbolKind::Trait)); | ||
359 | |||
360 | if trait_.is_unsafe(db) { | ||
361 | h |= HlMod::Unsafe; | ||
362 | } | ||
363 | |||
364 | h | ||
365 | } | ||
366 | hir::ModuleDef::TypeAlias(type_) => { | 378 | hir::ModuleDef::TypeAlias(type_) => { |
367 | let mut h = Highlight::new(HlTag::Symbol(SymbolKind::TypeAlias)); | 379 | let mut h = Highlight::new(HlTag::Symbol(SymbolKind::TypeAlias)); |
368 | 380 | ||
diff --git a/crates/ide/src/syntax_highlighting/html.rs b/crates/ide/src/syntax_highlighting/html.rs index 478facfee..21376a7ae 100644 --- a/crates/ide/src/syntax_highlighting/html.rs +++ b/crates/ide/src/syntax_highlighting/html.rs | |||
@@ -67,6 +67,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd | |||
67 | .field { color: #94BFF3; } | 67 | .field { color: #94BFF3; } |
68 | .function { color: #93E0E3; } | 68 | .function { color: #93E0E3; } |
69 | .function.unsafe { color: #BC8383; } | 69 | .function.unsafe { color: #BC8383; } |
70 | .trait.unsafe { color: #BC8383; } | ||
70 | .operator.unsafe { color: #BC8383; } | 71 | .operator.unsafe { color: #BC8383; } |
71 | .parameter { color: #94BFF3; } | 72 | .parameter { color: #94BFF3; } |
72 | .text { color: #DCDCCC; } | 73 | .text { color: #DCDCCC; } |
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_assoc_functions.html b/crates/ide/src/syntax_highlighting/test_data/highlight_assoc_functions.html index a0ea1db34..4e85f7c0b 100644 --- a/crates/ide/src/syntax_highlighting/test_data/highlight_assoc_functions.html +++ b/crates/ide/src/syntax_highlighting/test_data/highlight_assoc_functions.html | |||
@@ -15,6 +15,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd | |||
15 | .field { color: #94BFF3; } | 15 | .field { color: #94BFF3; } |
16 | .function { color: #93E0E3; } | 16 | .function { color: #93E0E3; } |
17 | .function.unsafe { color: #BC8383; } | 17 | .function.unsafe { color: #BC8383; } |
18 | .trait.unsafe { color: #BC8383; } | ||
18 | .operator.unsafe { color: #BC8383; } | 19 | .operator.unsafe { color: #BC8383; } |
19 | .parameter { color: #94BFF3; } | 20 | .parameter { color: #94BFF3; } |
20 | .text { color: #DCDCCC; } | 21 | .text { color: #DCDCCC; } |
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html b/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html index 921a956e6..79a285107 100644 --- a/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html +++ b/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html | |||
@@ -15,6 +15,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd | |||
15 | .field { color: #94BFF3; } | 15 | .field { color: #94BFF3; } |
16 | .function { color: #93E0E3; } | 16 | .function { color: #93E0E3; } |
17 | .function.unsafe { color: #BC8383; } | 17 | .function.unsafe { color: #BC8383; } |
18 | .trait.unsafe { color: #BC8383; } | ||
18 | .operator.unsafe { color: #BC8383; } | 19 | .operator.unsafe { color: #BC8383; } |
19 | .parameter { color: #94BFF3; } | 20 | .parameter { color: #94BFF3; } |
20 | .text { color: #DCDCCC; } | 21 | .text { color: #DCDCCC; } |
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_extern_crate.html b/crates/ide/src/syntax_highlighting/test_data/highlight_extern_crate.html index ca9bb1e7d..13f589cc0 100644 --- a/crates/ide/src/syntax_highlighting/test_data/highlight_extern_crate.html +++ b/crates/ide/src/syntax_highlighting/test_data/highlight_extern_crate.html | |||
@@ -15,6 +15,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd | |||
15 | .field { color: #94BFF3; } | 15 | .field { color: #94BFF3; } |
16 | .function { color: #93E0E3; } | 16 | .function { color: #93E0E3; } |
17 | .function.unsafe { color: #BC8383; } | 17 | .function.unsafe { color: #BC8383; } |
18 | .trait.unsafe { color: #BC8383; } | ||
18 | .operator.unsafe { color: #BC8383; } | 19 | .operator.unsafe { color: #BC8383; } |
19 | .parameter { color: #94BFF3; } | 20 | .parameter { color: #94BFF3; } |
20 | .text { color: #DCDCCC; } | 21 | .text { color: #DCDCCC; } |
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_injection.html b/crates/ide/src/syntax_highlighting/test_data/highlight_injection.html index 6202a03ce..50df376ae 100644 --- a/crates/ide/src/syntax_highlighting/test_data/highlight_injection.html +++ b/crates/ide/src/syntax_highlighting/test_data/highlight_injection.html | |||
@@ -15,6 +15,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd | |||
15 | .field { color: #94BFF3; } | 15 | .field { color: #94BFF3; } |
16 | .function { color: #93E0E3; } | 16 | .function { color: #93E0E3; } |
17 | .function.unsafe { color: #BC8383; } | 17 | .function.unsafe { color: #BC8383; } |
18 | .trait.unsafe { color: #BC8383; } | ||
18 | .operator.unsafe { color: #BC8383; } | 19 | .operator.unsafe { color: #BC8383; } |
19 | .parameter { color: #94BFF3; } | 20 | .parameter { color: #94BFF3; } |
20 | .text { color: #DCDCCC; } | 21 | .text { color: #DCDCCC; } |
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html b/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html index e860d713e..96cb09642 100644 --- a/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html +++ b/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html | |||
@@ -15,6 +15,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd | |||
15 | .field { color: #94BFF3; } | 15 | .field { color: #94BFF3; } |
16 | .function { color: #93E0E3; } | 16 | .function { color: #93E0E3; } |
17 | .function.unsafe { color: #BC8383; } | 17 | .function.unsafe { color: #BC8383; } |
18 | .trait.unsafe { color: #BC8383; } | ||
18 | .operator.unsafe { color: #BC8383; } | 19 | .operator.unsafe { color: #BC8383; } |
19 | .parameter { color: #94BFF3; } | 20 | .parameter { color: #94BFF3; } |
20 | .text { color: #DCDCCC; } | 21 | .text { color: #DCDCCC; } |
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html b/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html index 68165bdbf..55453468b 100644 --- a/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html +++ b/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html | |||
@@ -15,6 +15,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd | |||
15 | .field { color: #94BFF3; } | 15 | .field { color: #94BFF3; } |
16 | .function { color: #93E0E3; } | 16 | .function { color: #93E0E3; } |
17 | .function.unsafe { color: #BC8383; } | 17 | .function.unsafe { color: #BC8383; } |
18 | .trait.unsafe { color: #BC8383; } | ||
18 | .operator.unsafe { color: #BC8383; } | 19 | .operator.unsafe { color: #BC8383; } |
19 | .parameter { color: #94BFF3; } | 20 | .parameter { color: #94BFF3; } |
20 | .text { color: #DCDCCC; } | 21 | .text { color: #DCDCCC; } |
@@ -61,6 +62,11 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd | |||
61 | <span class="field declaration">a</span><span class="colon">:</span> <span class="builtin_type">u16</span><span class="comma">,</span> | 62 | <span class="field declaration">a</span><span class="colon">:</span> <span class="builtin_type">u16</span><span class="comma">,</span> |
62 | <span class="brace">}</span> | 63 | <span class="brace">}</span> |
63 | 64 | ||
65 | <span class="keyword unsafe">unsafe</span> <span class="keyword">trait</span> <span class="trait declaration unsafe">UnsafeTrait</span> <span class="brace">{</span><span class="brace">}</span> | ||
66 | <span class="keyword unsafe">unsafe</span> <span class="keyword">impl</span> <span class="trait unsafe">UnsafeTrait</span> <span class="keyword">for</span> <span class="struct">Packed</span> <span class="brace">{</span><span class="brace">}</span> | ||
67 | |||
68 | <span class="keyword">fn</span> <span class="function declaration">require_unsafe_trait</span><span class="angle"><</span><span class="type_param declaration">T</span><span class="colon">:</span> <span class="trait">UnsafeTrait</span><span class="angle">></span><span class="parenthesis">(</span><span class="punctuation">_</span><span class="colon">:</span> <span class="type_param">T</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span> | ||
69 | |||
64 | <span class="keyword">trait</span> <span class="trait declaration">DoTheAutoref</span> <span class="brace">{</span> | 70 | <span class="keyword">trait</span> <span class="trait declaration">DoTheAutoref</span> <span class="brace">{</span> |
65 | <span class="keyword">fn</span> <span class="function associated declaration trait">calls_autoref</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword declaration">self</span><span class="parenthesis">)</span><span class="semicolon">;</span> | 71 | <span class="keyword">fn</span> <span class="function associated declaration trait">calls_autoref</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword declaration">self</span><span class="parenthesis">)</span><span class="semicolon">;</span> |
66 | <span class="brace">}</span> | 72 | <span class="brace">}</span> |
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlighting.html b/crates/ide/src/syntax_highlighting/test_data/highlighting.html index 59f1e8e4c..9232cf905 100644 --- a/crates/ide/src/syntax_highlighting/test_data/highlighting.html +++ b/crates/ide/src/syntax_highlighting/test_data/highlighting.html | |||
@@ -15,6 +15,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd | |||
15 | .field { color: #94BFF3; } | 15 | .field { color: #94BFF3; } |
16 | .function { color: #93E0E3; } | 16 | .function { color: #93E0E3; } |
17 | .function.unsafe { color: #BC8383; } | 17 | .function.unsafe { color: #BC8383; } |
18 | .trait.unsafe { color: #BC8383; } | ||
18 | .operator.unsafe { color: #BC8383; } | 19 | .operator.unsafe { color: #BC8383; } |
19 | .parameter { color: #94BFF3; } | 20 | .parameter { color: #94BFF3; } |
20 | .text { color: #DCDCCC; } | 21 | .text { color: #DCDCCC; } |
diff --git a/crates/ide/src/syntax_highlighting/test_data/injection.html b/crates/ide/src/syntax_highlighting/test_data/injection.html index 9ab46d05c..082837328 100644 --- a/crates/ide/src/syntax_highlighting/test_data/injection.html +++ b/crates/ide/src/syntax_highlighting/test_data/injection.html | |||
@@ -15,6 +15,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd | |||
15 | .field { color: #94BFF3; } | 15 | .field { color: #94BFF3; } |
16 | .function { color: #93E0E3; } | 16 | .function { color: #93E0E3; } |
17 | .function.unsafe { color: #BC8383; } | 17 | .function.unsafe { color: #BC8383; } |
18 | .trait.unsafe { color: #BC8383; } | ||
18 | .operator.unsafe { color: #BC8383; } | 19 | .operator.unsafe { color: #BC8383; } |
19 | .parameter { color: #94BFF3; } | 20 | .parameter { color: #94BFF3; } |
20 | .text { color: #DCDCCC; } | 21 | .text { color: #DCDCCC; } |
diff --git a/crates/ide/src/syntax_highlighting/test_data/rainbow_highlighting.html b/crates/ide/src/syntax_highlighting/test_data/rainbow_highlighting.html index 666b0b228..763917714 100644 --- a/crates/ide/src/syntax_highlighting/test_data/rainbow_highlighting.html +++ b/crates/ide/src/syntax_highlighting/test_data/rainbow_highlighting.html | |||
@@ -15,6 +15,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd | |||
15 | .field { color: #94BFF3; } | 15 | .field { color: #94BFF3; } |
16 | .function { color: #93E0E3; } | 16 | .function { color: #93E0E3; } |
17 | .function.unsafe { color: #BC8383; } | 17 | .function.unsafe { color: #BC8383; } |
18 | .trait.unsafe { color: #BC8383; } | ||
18 | .operator.unsafe { color: #BC8383; } | 19 | .operator.unsafe { color: #BC8383; } |
19 | .parameter { color: #94BFF3; } | 20 | .parameter { color: #94BFF3; } |
20 | .text { color: #DCDCCC; } | 21 | .text { color: #DCDCCC; } |
diff --git a/crates/ide/src/syntax_highlighting/tests.rs b/crates/ide/src/syntax_highlighting/tests.rs index f7d8334a0..4f0b1ce85 100644 --- a/crates/ide/src/syntax_highlighting/tests.rs +++ b/crates/ide/src/syntax_highlighting/tests.rs | |||
@@ -527,6 +527,11 @@ struct Packed { | |||
527 | a: u16, | 527 | a: u16, |
528 | } | 528 | } |
529 | 529 | ||
530 | unsafe trait UnsafeTrait {} | ||
531 | unsafe impl UnsafeTrait for Packed {} | ||
532 | |||
533 | fn require_unsafe_trait<T: UnsafeTrait>(_: T) {} | ||
534 | |||
530 | trait DoTheAutoref { | 535 | trait DoTheAutoref { |
531 | fn calls_autoref(&self); | 536 | fn calls_autoref(&self); |
532 | } | 537 | } |
diff --git a/crates/ide_assists/src/handlers/fix_visibility.rs b/crates/ide_assists/src/handlers/fix_visibility.rs index 9b432e92f..f834bf16a 100644 --- a/crates/ide_assists/src/handlers/fix_visibility.rs +++ b/crates/ide_assists/src/handlers/fix_visibility.rs | |||
@@ -361,8 +361,6 @@ pub struct Foo { pub bar: () } | |||
361 | } | 361 | } |
362 | 362 | ||
363 | #[test] | 363 | #[test] |
364 | #[ignore] | ||
365 | // FIXME reenable this test when `Semantics::resolve_record_field` works with union fields | ||
366 | fn fix_visibility_of_union_field() { | 364 | fn fix_visibility_of_union_field() { |
367 | check_assist( | 365 | check_assist( |
368 | fix_visibility, | 366 | fix_visibility, |
@@ -583,25 +581,25 @@ pub struct Foo { pub(crate) bar: () } | |||
583 | } | 581 | } |
584 | 582 | ||
585 | #[test] | 583 | #[test] |
586 | #[ignore] | ||
587 | // FIXME handle reexports properly | ||
588 | fn fix_visibility_of_reexport() { | 584 | fn fix_visibility_of_reexport() { |
585 | // FIXME: broken test, this should fix visibility of the re-export | ||
586 | // rather than the struct. | ||
589 | check_assist( | 587 | check_assist( |
590 | fix_visibility, | 588 | fix_visibility, |
591 | r" | 589 | r#" |
592 | mod foo { | 590 | mod foo { |
593 | use bar::Baz; | 591 | use bar::Baz; |
594 | mod bar { pub(super) struct Baz; } | 592 | mod bar { pub(super) struct Baz; } |
595 | } | 593 | } |
596 | foo::Baz$0 | 594 | foo::Baz$0 |
597 | ", | 595 | "#, |
598 | r" | 596 | r#" |
599 | mod foo { | 597 | mod foo { |
600 | $0pub(crate) use bar::Baz; | 598 | use bar::Baz; |
601 | mod bar { pub(super) struct Baz; } | 599 | mod bar { $0pub(crate) struct Baz; } |
602 | } | 600 | } |
603 | foo::Baz | 601 | foo::Baz |
604 | ", | 602 | "#, |
605 | ) | 603 | ) |
606 | } | 604 | } |
607 | } | 605 | } |
diff --git a/crates/ide_assists/src/handlers/generate_function.rs b/crates/ide_assists/src/handlers/generate_function.rs index 706c995ac..6a658d4cf 100644 --- a/crates/ide_assists/src/handlers/generate_function.rs +++ b/crates/ide_assists/src/handlers/generate_function.rs | |||
@@ -811,9 +811,8 @@ fn bar(baz: Baz::Bof) ${0:-> ()} { | |||
811 | } | 811 | } |
812 | 812 | ||
813 | #[test] | 813 | #[test] |
814 | #[ignore] | ||
815 | // FIXME fix printing the generics of a `Ty` to make this test pass | ||
816 | fn add_function_with_generic_arg() { | 814 | fn add_function_with_generic_arg() { |
815 | // FIXME: This is wrong, generated `bar` should include generic parameter. | ||
817 | check_assist( | 816 | check_assist( |
818 | generate_function, | 817 | generate_function, |
819 | r" | 818 | r" |
@@ -826,7 +825,7 @@ fn foo<T>(t: T) { | |||
826 | bar(t) | 825 | bar(t) |
827 | } | 826 | } |
828 | 827 | ||
829 | fn bar<T>(t: T) ${0:-> ()} { | 828 | fn bar(t: T) ${0:-> ()} { |
830 | todo!() | 829 | todo!() |
831 | } | 830 | } |
832 | ", | 831 | ", |
@@ -834,9 +833,8 @@ fn bar<T>(t: T) ${0:-> ()} { | |||
834 | } | 833 | } |
835 | 834 | ||
836 | #[test] | 835 | #[test] |
837 | #[ignore] | ||
838 | // FIXME Fix function type printing to make this test pass | ||
839 | fn add_function_with_fn_arg() { | 836 | fn add_function_with_fn_arg() { |
837 | // FIXME: The argument in `bar` is wrong. | ||
840 | check_assist( | 838 | check_assist( |
841 | generate_function, | 839 | generate_function, |
842 | r" | 840 | r" |
@@ -857,7 +855,7 @@ fn foo() { | |||
857 | bar(Baz::new); | 855 | bar(Baz::new); |
858 | } | 856 | } |
859 | 857 | ||
860 | fn bar(arg: fn() -> Baz) ${0:-> ()} { | 858 | fn bar(new: fn) ${0:-> ()} { |
861 | todo!() | 859 | todo!() |
862 | } | 860 | } |
863 | ", | 861 | ", |
@@ -865,9 +863,8 @@ fn bar(arg: fn() -> Baz) ${0:-> ()} { | |||
865 | } | 863 | } |
866 | 864 | ||
867 | #[test] | 865 | #[test] |
868 | #[ignore] | ||
869 | // FIXME Fix closure type printing to make this test pass | ||
870 | fn add_function_with_closure_arg() { | 866 | fn add_function_with_closure_arg() { |
867 | // FIXME: The argument in `bar` is wrong. | ||
871 | check_assist( | 868 | check_assist( |
872 | generate_function, | 869 | generate_function, |
873 | r" | 870 | r" |
@@ -882,7 +879,7 @@ fn foo() { | |||
882 | bar(closure) | 879 | bar(closure) |
883 | } | 880 | } |
884 | 881 | ||
885 | fn bar(closure: impl Fn(i64) -> i64) ${0:-> ()} { | 882 | fn bar(closure: ()) ${0:-> ()} { |
886 | todo!() | 883 | todo!() |
887 | } | 884 | } |
888 | ", | 885 | ", |
@@ -986,13 +983,10 @@ fn foo() { | |||
986 | } | 983 | } |
987 | 984 | ||
988 | #[test] | 985 | #[test] |
989 | #[ignore] | ||
990 | // Ignored until local imports are supported. | ||
991 | // See https://github.com/rust-analyzer/rust-analyzer/issues/1165 | ||
992 | fn qualified_path_uses_correct_scope() { | 986 | fn qualified_path_uses_correct_scope() { |
993 | check_assist( | 987 | check_assist( |
994 | generate_function, | 988 | generate_function, |
995 | " | 989 | r#" |
996 | mod foo { | 990 | mod foo { |
997 | pub struct Foo; | 991 | pub struct Foo; |
998 | } | 992 | } |
@@ -1001,8 +995,8 @@ fn bar() { | |||
1001 | let foo = Foo; | 995 | let foo = Foo; |
1002 | baz$0(foo) | 996 | baz$0(foo) |
1003 | } | 997 | } |
1004 | ", | 998 | "#, |
1005 | " | 999 | r#" |
1006 | mod foo { | 1000 | mod foo { |
1007 | pub struct Foo; | 1001 | pub struct Foo; |
1008 | } | 1002 | } |
@@ -1015,7 +1009,7 @@ fn bar() { | |||
1015 | fn baz(foo: foo::Foo) ${0:-> ()} { | 1009 | fn baz(foo: foo::Foo) ${0:-> ()} { |
1016 | todo!() | 1010 | todo!() |
1017 | } | 1011 | } |
1018 | ", | 1012 | "#, |
1019 | ) | 1013 | ) |
1020 | } | 1014 | } |
1021 | 1015 | ||
@@ -1141,40 +1135,29 @@ fn bar() {} | |||
1141 | // The assist is only active if the cursor is on an unresolved path, | 1135 | // The assist is only active if the cursor is on an unresolved path, |
1142 | // but the assist should only be offered if the path is a function call. | 1136 | // but the assist should only be offered if the path is a function call. |
1143 | generate_function, | 1137 | generate_function, |
1144 | r" | 1138 | r#" |
1145 | fn foo() { | 1139 | fn foo() { |
1146 | bar(b$0az); | 1140 | bar(b$0az); |
1147 | } | 1141 | } |
1148 | 1142 | ||
1149 | fn bar(baz: ()) {} | 1143 | fn bar(baz: ()) {} |
1150 | ", | 1144 | "#, |
1151 | ) | 1145 | ) |
1152 | } | 1146 | } |
1153 | 1147 | ||
1154 | #[test] | 1148 | #[test] |
1155 | #[ignore] | ||
1156 | fn create_method_with_no_args() { | 1149 | fn create_method_with_no_args() { |
1157 | check_assist( | 1150 | // FIXME: This is wrong, this should just work. |
1151 | check_assist_not_applicable( | ||
1158 | generate_function, | 1152 | generate_function, |
1159 | r" | 1153 | r#" |
1160 | struct Foo; | 1154 | struct Foo; |
1161 | impl Foo { | 1155 | impl Foo { |
1162 | fn foo(&self) { | 1156 | fn foo(&self) { |
1163 | self.bar()$0; | 1157 | self.bar()$0; |
1164 | } | 1158 | } |
1165 | } | 1159 | } |
1166 | ", | 1160 | "#, |
1167 | r" | ||
1168 | struct Foo; | ||
1169 | impl Foo { | ||
1170 | fn foo(&self) { | ||
1171 | self.bar(); | ||
1172 | } | ||
1173 | fn bar(&self) { | ||
1174 | todo!(); | ||
1175 | } | ||
1176 | } | ||
1177 | ", | ||
1178 | ) | 1161 | ) |
1179 | } | 1162 | } |
1180 | } | 1163 | } |
diff --git a/crates/ide_assists/src/handlers/qualify_path.rs b/crates/ide_assists/src/handlers/qualify_path.rs index f91770a76..1d7be183a 100644 --- a/crates/ide_assists/src/handlers/qualify_path.rs +++ b/crates/ide_assists/src/handlers/qualify_path.rs | |||
@@ -216,28 +216,28 @@ mod tests { | |||
216 | cov_mark::check!(qualify_path_unqualified_name); | 216 | cov_mark::check!(qualify_path_unqualified_name); |
217 | check_assist( | 217 | check_assist( |
218 | qualify_path, | 218 | qualify_path, |
219 | r" | 219 | r#" |
220 | mod std { | 220 | mod std { |
221 | pub mod fmt { | 221 | pub mod fmt { |
222 | pub struct Formatter; | 222 | pub struct Formatter; |
223 | } | 223 | } |
224 | } | 224 | } |
225 | 225 | ||
226 | use std::fmt; | 226 | use std::fmt; |
227 | 227 | ||
228 | $0Formatter | 228 | $0Formatter |
229 | ", | 229 | "#, |
230 | r" | 230 | r#" |
231 | mod std { | 231 | mod std { |
232 | pub mod fmt { | 232 | pub mod fmt { |
233 | pub struct Formatter; | 233 | pub struct Formatter; |
234 | } | 234 | } |
235 | } | 235 | } |
236 | 236 | ||
237 | use std::fmt; | 237 | use std::fmt; |
238 | 238 | ||
239 | fmt::Formatter | 239 | fmt::Formatter |
240 | ", | 240 | "#, |
241 | ); | 241 | ); |
242 | } | 242 | } |
243 | 243 | ||
@@ -245,20 +245,20 @@ mod tests { | |||
245 | fn applicable_when_found_an_import() { | 245 | fn applicable_when_found_an_import() { |
246 | check_assist( | 246 | check_assist( |
247 | qualify_path, | 247 | qualify_path, |
248 | r" | 248 | r#" |
249 | $0PubStruct | 249 | $0PubStruct |
250 | 250 | ||
251 | pub mod PubMod { | 251 | pub mod PubMod { |
252 | pub struct PubStruct; | 252 | pub struct PubStruct; |
253 | } | 253 | } |
254 | ", | 254 | "#, |
255 | r" | 255 | r#" |
256 | PubMod::PubStruct | 256 | PubMod::PubStruct |
257 | 257 | ||
258 | pub mod PubMod { | 258 | pub mod PubMod { |
259 | pub struct PubStruct; | 259 | pub struct PubStruct; |
260 | } | 260 | } |
261 | ", | 261 | "#, |
262 | ); | 262 | ); |
263 | } | 263 | } |
264 | 264 | ||
@@ -266,26 +266,26 @@ mod tests { | |||
266 | fn applicable_in_macros() { | 266 | fn applicable_in_macros() { |
267 | check_assist( | 267 | check_assist( |
268 | qualify_path, | 268 | qualify_path, |
269 | r" | 269 | r#" |
270 | macro_rules! foo { | 270 | macro_rules! foo { |
271 | ($i:ident) => { fn foo(a: $i) {} } | 271 | ($i:ident) => { fn foo(a: $i) {} } |
272 | } | 272 | } |
273 | foo!(Pub$0Struct); | 273 | foo!(Pub$0Struct); |
274 | 274 | ||
275 | pub mod PubMod { | 275 | pub mod PubMod { |
276 | pub struct PubStruct; | 276 | pub struct PubStruct; |
277 | } | 277 | } |
278 | ", | 278 | "#, |
279 | r" | 279 | r#" |
280 | macro_rules! foo { | 280 | macro_rules! foo { |
281 | ($i:ident) => { fn foo(a: $i) {} } | 281 | ($i:ident) => { fn foo(a: $i) {} } |
282 | } | 282 | } |
283 | foo!(PubMod::PubStruct); | 283 | foo!(PubMod::PubStruct); |
284 | 284 | ||
285 | pub mod PubMod { | 285 | pub mod PubMod { |
286 | pub struct PubStruct; | 286 | pub struct PubStruct; |
287 | } | 287 | } |
288 | ", | 288 | "#, |
289 | ); | 289 | ); |
290 | } | 290 | } |
291 | 291 | ||
@@ -293,32 +293,32 @@ mod tests { | |||
293 | fn applicable_when_found_multiple_imports() { | 293 | fn applicable_when_found_multiple_imports() { |
294 | check_assist( | 294 | check_assist( |
295 | qualify_path, | 295 | qualify_path, |
296 | r" | 296 | r#" |
297 | PubSt$0ruct | 297 | PubSt$0ruct |
298 | 298 | ||
299 | pub mod PubMod1 { | 299 | pub mod PubMod1 { |
300 | pub struct PubStruct; | 300 | pub struct PubStruct; |
301 | } | 301 | } |
302 | pub mod PubMod2 { | 302 | pub mod PubMod2 { |
303 | pub struct PubStruct; | 303 | pub struct PubStruct; |
304 | } | 304 | } |
305 | pub mod PubMod3 { | 305 | pub mod PubMod3 { |
306 | pub struct PubStruct; | 306 | pub struct PubStruct; |
307 | } | 307 | } |
308 | ", | 308 | "#, |
309 | r" | 309 | r#" |
310 | PubMod3::PubStruct | 310 | PubMod3::PubStruct |
311 | 311 | ||
312 | pub mod PubMod1 { | 312 | pub mod PubMod1 { |
313 | pub struct PubStruct; | 313 | pub struct PubStruct; |
314 | } | 314 | } |
315 | pub mod PubMod2 { | 315 | pub mod PubMod2 { |
316 | pub struct PubStruct; | 316 | pub struct PubStruct; |
317 | } | 317 | } |
318 | pub mod PubMod3 { | 318 | pub mod PubMod3 { |
319 | pub struct PubStruct; | 319 | pub struct PubStruct; |
320 | } | 320 | } |
321 | ", | 321 | "#, |
322 | ); | 322 | ); |
323 | } | 323 | } |
324 | 324 | ||
@@ -326,15 +326,15 @@ mod tests { | |||
326 | fn not_applicable_for_already_imported_types() { | 326 | fn not_applicable_for_already_imported_types() { |
327 | check_assist_not_applicable( | 327 | check_assist_not_applicable( |
328 | qualify_path, | 328 | qualify_path, |
329 | r" | 329 | r#" |
330 | use PubMod::PubStruct; | 330 | use PubMod::PubStruct; |
331 | 331 | ||
332 | PubStruct$0 | 332 | PubStruct$0 |
333 | 333 | ||
334 | pub mod PubMod { | 334 | pub mod PubMod { |
335 | pub struct PubStruct; | 335 | pub struct PubStruct; |
336 | } | 336 | } |
337 | ", | 337 | "#, |
338 | ); | 338 | ); |
339 | } | 339 | } |
340 | 340 | ||
@@ -342,35 +342,32 @@ mod tests { | |||
342 | fn not_applicable_for_types_with_private_paths() { | 342 | fn not_applicable_for_types_with_private_paths() { |
343 | check_assist_not_applicable( | 343 | check_assist_not_applicable( |
344 | qualify_path, | 344 | qualify_path, |
345 | r" | 345 | r#" |
346 | PrivateStruct$0 | 346 | PrivateStruct$0 |
347 | 347 | ||
348 | pub mod PubMod { | 348 | pub mod PubMod { |
349 | struct PrivateStruct; | 349 | struct PrivateStruct; |
350 | } | 350 | } |
351 | ", | 351 | "#, |
352 | ); | 352 | ); |
353 | } | 353 | } |
354 | 354 | ||
355 | #[test] | 355 | #[test] |
356 | fn not_applicable_when_no_imports_found() { | 356 | fn not_applicable_when_no_imports_found() { |
357 | check_assist_not_applicable( | 357 | check_assist_not_applicable(qualify_path, r#"PubStruct$0"#); |
358 | qualify_path, | ||
359 | " | ||
360 | PubStruct$0", | ||
361 | ); | ||
362 | } | 358 | } |
363 | 359 | ||
364 | #[test] | 360 | #[test] |
365 | fn not_applicable_in_import_statements() { | 361 | fn not_applicable_in_import_statements() { |
366 | check_assist_not_applicable( | 362 | check_assist_not_applicable( |
367 | qualify_path, | 363 | qualify_path, |
368 | r" | 364 | r#" |
369 | use PubStruct$0; | 365 | use PubStruct$0; |
370 | 366 | ||
371 | pub mod PubMod { | 367 | pub mod PubMod { |
372 | pub struct PubStruct; | 368 | pub struct PubStruct; |
373 | }", | 369 | } |
370 | "#, | ||
374 | ); | 371 | ); |
375 | } | 372 | } |
376 | 373 | ||
@@ -378,20 +375,20 @@ mod tests { | |||
378 | fn qualify_function() { | 375 | fn qualify_function() { |
379 | check_assist( | 376 | check_assist( |
380 | qualify_path, | 377 | qualify_path, |
381 | r" | 378 | r#" |
382 | test_function$0 | 379 | test_function$0 |
383 | 380 | ||
384 | pub mod PubMod { | 381 | pub mod PubMod { |
385 | pub fn test_function() {}; | 382 | pub fn test_function() {}; |
386 | } | 383 | } |
387 | ", | 384 | "#, |
388 | r" | 385 | r#" |
389 | PubMod::test_function | 386 | PubMod::test_function |
390 | 387 | ||
391 | pub mod PubMod { | 388 | pub mod PubMod { |
392 | pub fn test_function() {}; | 389 | pub fn test_function() {}; |
393 | } | 390 | } |
394 | ", | 391 | "#, |
395 | ); | 392 | ); |
396 | } | 393 | } |
397 | 394 | ||
@@ -399,7 +396,7 @@ mod tests { | |||
399 | fn qualify_macro() { | 396 | fn qualify_macro() { |
400 | check_assist( | 397 | check_assist( |
401 | qualify_path, | 398 | qualify_path, |
402 | r" | 399 | r#" |
403 | //- /lib.rs crate:crate_with_macro | 400 | //- /lib.rs crate:crate_with_macro |
404 | #[macro_export] | 401 | #[macro_export] |
405 | macro_rules! foo { | 402 | macro_rules! foo { |
@@ -410,12 +407,12 @@ macro_rules! foo { | |||
410 | fn main() { | 407 | fn main() { |
411 | foo$0 | 408 | foo$0 |
412 | } | 409 | } |
413 | ", | 410 | "#, |
414 | r" | 411 | r#" |
415 | fn main() { | 412 | fn main() { |
416 | crate_with_macro::foo | 413 | crate_with_macro::foo |
417 | } | 414 | } |
418 | ", | 415 | "#, |
419 | ); | 416 | ); |
420 | } | 417 | } |
421 | 418 | ||
@@ -423,13 +420,13 @@ fn main() { | |||
423 | fn qualify_path_target() { | 420 | fn qualify_path_target() { |
424 | check_assist_target( | 421 | check_assist_target( |
425 | qualify_path, | 422 | qualify_path, |
426 | r" | 423 | r#" |
427 | struct AssistInfo { | 424 | struct AssistInfo { |
428 | group_label: Option<$0GroupLabel>, | 425 | group_label: Option<$0GroupLabel>, |
429 | } | 426 | } |
430 | 427 | ||
431 | mod m { pub struct GroupLabel; } | 428 | mod m { pub struct GroupLabel; } |
432 | ", | 429 | "#, |
433 | "GroupLabel", | 430 | "GroupLabel", |
434 | ) | 431 | ) |
435 | } | 432 | } |
@@ -438,20 +435,20 @@ fn main() { | |||
438 | fn not_applicable_when_path_start_is_imported() { | 435 | fn not_applicable_when_path_start_is_imported() { |
439 | check_assist_not_applicable( | 436 | check_assist_not_applicable( |
440 | qualify_path, | 437 | qualify_path, |
441 | r" | 438 | r#" |
442 | pub mod mod1 { | 439 | pub mod mod1 { |
443 | pub mod mod2 { | 440 | pub mod mod2 { |
444 | pub mod mod3 { | 441 | pub mod mod3 { |
445 | pub struct TestStruct; | 442 | pub struct TestStruct; |
446 | } | 443 | } |
447 | } | 444 | } |
448 | } | 445 | } |
449 | 446 | ||
450 | use mod1::mod2; | 447 | use mod1::mod2; |
451 | fn main() { | 448 | fn main() { |
452 | mod2::mod3::TestStruct$0 | 449 | mod2::mod3::TestStruct$0 |
453 | } | 450 | } |
454 | ", | 451 | "#, |
455 | ); | 452 | ); |
456 | } | 453 | } |
457 | 454 | ||
@@ -459,16 +456,16 @@ fn main() { | |||
459 | fn not_applicable_for_imported_function() { | 456 | fn not_applicable_for_imported_function() { |
460 | check_assist_not_applicable( | 457 | check_assist_not_applicable( |
461 | qualify_path, | 458 | qualify_path, |
462 | r" | 459 | r#" |
463 | pub mod test_mod { | 460 | pub mod test_mod { |
464 | pub fn test_function() {} | 461 | pub fn test_function() {} |
465 | } | 462 | } |
466 | 463 | ||
467 | use test_mod::test_function; | 464 | use test_mod::test_function; |
468 | fn main() { | 465 | fn main() { |
469 | test_function$0 | 466 | test_function$0 |
470 | } | 467 | } |
471 | ", | 468 | "#, |
472 | ); | 469 | ); |
473 | } | 470 | } |
474 | 471 | ||
@@ -476,30 +473,30 @@ fn main() { | |||
476 | fn associated_struct_function() { | 473 | fn associated_struct_function() { |
477 | check_assist( | 474 | check_assist( |
478 | qualify_path, | 475 | qualify_path, |
479 | r" | 476 | r#" |
480 | mod test_mod { | 477 | mod test_mod { |
481 | pub struct TestStruct {} | 478 | pub struct TestStruct {} |
482 | impl TestStruct { | 479 | impl TestStruct { |
483 | pub fn test_function() {} | 480 | pub fn test_function() {} |
484 | } | 481 | } |
485 | } | 482 | } |
486 | 483 | ||
487 | fn main() { | 484 | fn main() { |
488 | TestStruct::test_function$0 | 485 | TestStruct::test_function$0 |
489 | } | 486 | } |
490 | ", | 487 | "#, |
491 | r" | 488 | r#" |
492 | mod test_mod { | 489 | mod test_mod { |
493 | pub struct TestStruct {} | 490 | pub struct TestStruct {} |
494 | impl TestStruct { | 491 | impl TestStruct { |
495 | pub fn test_function() {} | 492 | pub fn test_function() {} |
496 | } | 493 | } |
497 | } | 494 | } |
498 | 495 | ||
499 | fn main() { | 496 | fn main() { |
500 | test_mod::TestStruct::test_function | 497 | test_mod::TestStruct::test_function |
501 | } | 498 | } |
502 | ", | 499 | "#, |
503 | ); | 500 | ); |
504 | } | 501 | } |
505 | 502 | ||
@@ -508,62 +505,50 @@ fn main() { | |||
508 | cov_mark::check!(qualify_path_qualifier_start); | 505 | cov_mark::check!(qualify_path_qualifier_start); |
509 | check_assist( | 506 | check_assist( |
510 | qualify_path, | 507 | qualify_path, |
511 | r" | 508 | r#" |
512 | mod test_mod { | 509 | mod test_mod { |
513 | pub struct TestStruct {} | 510 | pub struct TestStruct {} |
514 | impl TestStruct { | 511 | impl TestStruct { |
515 | const TEST_CONST: u8 = 42; | 512 | const TEST_CONST: u8 = 42; |
516 | } | 513 | } |
517 | } | 514 | } |
518 | 515 | ||
519 | fn main() { | 516 | fn main() { |
520 | TestStruct::TEST_CONST$0 | 517 | TestStruct::TEST_CONST$0 |
521 | } | 518 | } |
522 | ", | 519 | "#, |
523 | r" | 520 | r#" |
524 | mod test_mod { | 521 | mod test_mod { |
525 | pub struct TestStruct {} | 522 | pub struct TestStruct {} |
526 | impl TestStruct { | 523 | impl TestStruct { |
527 | const TEST_CONST: u8 = 42; | 524 | const TEST_CONST: u8 = 42; |
528 | } | 525 | } |
529 | } | 526 | } |
530 | 527 | ||
531 | fn main() { | 528 | fn main() { |
532 | test_mod::TestStruct::TEST_CONST | 529 | test_mod::TestStruct::TEST_CONST |
533 | } | 530 | } |
534 | ", | 531 | "#, |
535 | ); | 532 | ); |
536 | } | 533 | } |
537 | 534 | ||
538 | #[test] | 535 | #[test] |
539 | #[ignore = "FIXME: non-trait assoc items completion is unsupported yet, see FIXME in the import_assets.rs for more details"] | ||
540 | fn associated_struct_const_unqualified() { | 536 | fn associated_struct_const_unqualified() { |
541 | check_assist( | 537 | // FIXME: non-trait assoc items completion is unsupported yet, see FIXME in the import_assets.rs for more details |
538 | check_assist_not_applicable( | ||
542 | qualify_path, | 539 | qualify_path, |
543 | r" | 540 | r#" |
544 | mod test_mod { | 541 | mod test_mod { |
545 | pub struct TestStruct {} | 542 | pub struct TestStruct {} |
546 | impl TestStruct { | 543 | impl TestStruct { |
547 | const TEST_CONST: u8 = 42; | 544 | const TEST_CONST: u8 = 42; |
548 | } | 545 | } |
549 | } | 546 | } |
550 | |||
551 | fn main() { | ||
552 | TEST_CONST$0 | ||
553 | } | ||
554 | ", | ||
555 | r" | ||
556 | mod test_mod { | ||
557 | pub struct TestStruct {} | ||
558 | impl TestStruct { | ||
559 | const TEST_CONST: u8 = 42; | ||
560 | } | ||
561 | } | ||
562 | 547 | ||
563 | fn main() { | 548 | fn main() { |
564 | test_mod::TestStruct::TEST_CONST | 549 | TEST_CONST$0 |
565 | } | 550 | } |
566 | ", | 551 | "#, |
567 | ); | 552 | ); |
568 | } | 553 | } |
569 | 554 | ||
@@ -571,36 +556,36 @@ fn main() { | |||
571 | fn associated_trait_function() { | 556 | fn associated_trait_function() { |
572 | check_assist( | 557 | check_assist( |
573 | qualify_path, | 558 | qualify_path, |
574 | r" | 559 | r#" |
575 | mod test_mod { | 560 | mod test_mod { |
576 | pub trait TestTrait { | 561 | pub trait TestTrait { |
577 | fn test_function(); | 562 | fn test_function(); |
578 | } | 563 | } |
579 | pub struct TestStruct {} | 564 | pub struct TestStruct {} |
580 | impl TestTrait for TestStruct { | 565 | impl TestTrait for TestStruct { |
581 | fn test_function() {} | 566 | fn test_function() {} |
582 | } | 567 | } |
583 | } | 568 | } |
584 | 569 | ||
585 | fn main() { | 570 | fn main() { |
586 | test_mod::TestStruct::test_function$0 | 571 | test_mod::TestStruct::test_function$0 |
587 | } | 572 | } |
588 | ", | 573 | "#, |
589 | r" | 574 | r#" |
590 | mod test_mod { | 575 | mod test_mod { |
591 | pub trait TestTrait { | 576 | pub trait TestTrait { |
592 | fn test_function(); | 577 | fn test_function(); |
593 | } | 578 | } |
594 | pub struct TestStruct {} | 579 | pub struct TestStruct {} |
595 | impl TestTrait for TestStruct { | 580 | impl TestTrait for TestStruct { |
596 | fn test_function() {} | 581 | fn test_function() {} |
597 | } | 582 | } |
598 | } | 583 | } |
599 | 584 | ||
600 | fn main() { | 585 | fn main() { |
601 | <test_mod::TestStruct as test_mod::TestTrait>::test_function | 586 | <test_mod::TestStruct as test_mod::TestTrait>::test_function |
602 | } | 587 | } |
603 | ", | 588 | "#, |
604 | ); | 589 | ); |
605 | } | 590 | } |
606 | 591 | ||
@@ -608,31 +593,31 @@ fn main() { | |||
608 | fn not_applicable_for_imported_trait_for_function() { | 593 | fn not_applicable_for_imported_trait_for_function() { |
609 | check_assist_not_applicable( | 594 | check_assist_not_applicable( |
610 | qualify_path, | 595 | qualify_path, |
611 | r" | 596 | r#" |
612 | mod test_mod { | 597 | mod test_mod { |
613 | pub trait TestTrait { | 598 | pub trait TestTrait { |
614 | fn test_function(); | 599 | fn test_function(); |
615 | } | 600 | } |
616 | pub trait TestTrait2 { | 601 | pub trait TestTrait2 { |
617 | fn test_function(); | 602 | fn test_function(); |
618 | } | 603 | } |
619 | pub enum TestEnum { | 604 | pub enum TestEnum { |
620 | One, | 605 | One, |
621 | Two, | 606 | Two, |
622 | } | 607 | } |
623 | impl TestTrait2 for TestEnum { | 608 | impl TestTrait2 for TestEnum { |
624 | fn test_function() {} | 609 | fn test_function() {} |
625 | } | 610 | } |
626 | impl TestTrait for TestEnum { | 611 | impl TestTrait for TestEnum { |
627 | fn test_function() {} | 612 | fn test_function() {} |
628 | } | 613 | } |
629 | } | 614 | } |
630 | 615 | ||
631 | use test_mod::TestTrait2; | 616 | use test_mod::TestTrait2; |
632 | fn main() { | 617 | fn main() { |
633 | test_mod::TestEnum::test_function$0; | 618 | test_mod::TestEnum::test_function$0; |
634 | } | 619 | } |
635 | ", | 620 | "#, |
636 | ) | 621 | ) |
637 | } | 622 | } |
638 | 623 | ||
@@ -641,36 +626,36 @@ fn main() { | |||
641 | cov_mark::check!(qualify_path_trait_assoc_item); | 626 | cov_mark::check!(qualify_path_trait_assoc_item); |
642 | check_assist( | 627 | check_assist( |
643 | qualify_path, | 628 | qualify_path, |
644 | r" | 629 | r#" |
645 | mod test_mod { | 630 | mod test_mod { |
646 | pub trait TestTrait { | 631 | pub trait TestTrait { |
647 | const TEST_CONST: u8; | 632 | const TEST_CONST: u8; |
648 | } | 633 | } |
649 | pub struct TestStruct {} | 634 | pub struct TestStruct {} |
650 | impl TestTrait for TestStruct { | 635 | impl TestTrait for TestStruct { |
651 | const TEST_CONST: u8 = 42; | 636 | const TEST_CONST: u8 = 42; |
652 | } | 637 | } |
653 | } | 638 | } |
654 | 639 | ||
655 | fn main() { | 640 | fn main() { |
656 | test_mod::TestStruct::TEST_CONST$0 | 641 | test_mod::TestStruct::TEST_CONST$0 |
657 | } | 642 | } |
658 | ", | 643 | "#, |
659 | r" | 644 | r#" |
660 | mod test_mod { | 645 | mod test_mod { |
661 | pub trait TestTrait { | 646 | pub trait TestTrait { |
662 | const TEST_CONST: u8; | 647 | const TEST_CONST: u8; |
663 | } | 648 | } |
664 | pub struct TestStruct {} | 649 | pub struct TestStruct {} |
665 | impl TestTrait for TestStruct { | 650 | impl TestTrait for TestStruct { |
666 | const TEST_CONST: u8 = 42; | 651 | const TEST_CONST: u8 = 42; |
667 | } | 652 | } |
668 | } | 653 | } |
669 | 654 | ||
670 | fn main() { | 655 | fn main() { |
671 | <test_mod::TestStruct as test_mod::TestTrait>::TEST_CONST | 656 | <test_mod::TestStruct as test_mod::TestTrait>::TEST_CONST |
672 | } | 657 | } |
673 | ", | 658 | "#, |
674 | ); | 659 | ); |
675 | } | 660 | } |
676 | 661 | ||
@@ -678,31 +663,31 @@ fn main() { | |||
678 | fn not_applicable_for_imported_trait_for_const() { | 663 | fn not_applicable_for_imported_trait_for_const() { |
679 | check_assist_not_applicable( | 664 | check_assist_not_applicable( |
680 | qualify_path, | 665 | qualify_path, |
681 | r" | 666 | r#" |
682 | mod test_mod { | 667 | mod test_mod { |
683 | pub trait TestTrait { | 668 | pub trait TestTrait { |
684 | const TEST_CONST: u8; | 669 | const TEST_CONST: u8; |
685 | } | 670 | } |
686 | pub trait TestTrait2 { | 671 | pub trait TestTrait2 { |
687 | const TEST_CONST: f64; | 672 | const TEST_CONST: f64; |
688 | } | 673 | } |
689 | pub enum TestEnum { | 674 | pub enum TestEnum { |
690 | One, | 675 | One, |
691 | Two, | 676 | Two, |
692 | } | 677 | } |
693 | impl TestTrait2 for TestEnum { | 678 | impl TestTrait2 for TestEnum { |
694 | const TEST_CONST: f64 = 42.0; | 679 | const TEST_CONST: f64 = 42.0; |
695 | } | 680 | } |
696 | impl TestTrait for TestEnum { | 681 | impl TestTrait for TestEnum { |
697 | const TEST_CONST: u8 = 42; | 682 | const TEST_CONST: u8 = 42; |
698 | } | 683 | } |
699 | } | 684 | } |
700 | 685 | ||
701 | use test_mod::TestTrait2; | 686 | use test_mod::TestTrait2; |
702 | fn main() { | 687 | fn main() { |
703 | test_mod::TestEnum::TEST_CONST$0; | 688 | test_mod::TestEnum::TEST_CONST$0; |
704 | } | 689 | } |
705 | ", | 690 | "#, |
706 | ) | 691 | ) |
707 | } | 692 | } |
708 | 693 | ||
@@ -711,38 +696,38 @@ fn main() { | |||
711 | cov_mark::check!(qualify_path_trait_method); | 696 | cov_mark::check!(qualify_path_trait_method); |
712 | check_assist( | 697 | check_assist( |
713 | qualify_path, | 698 | qualify_path, |
714 | r" | 699 | r#" |
715 | mod test_mod { | 700 | mod test_mod { |
716 | pub trait TestTrait { | 701 | pub trait TestTrait { |
717 | fn test_method(&self); | 702 | fn test_method(&self); |
718 | } | 703 | } |
719 | pub struct TestStruct {} | 704 | pub struct TestStruct {} |
720 | impl TestTrait for TestStruct { | 705 | impl TestTrait for TestStruct { |
721 | fn test_method(&self) {} | 706 | fn test_method(&self) {} |
722 | } | 707 | } |
723 | } | 708 | } |
724 | 709 | ||
725 | fn main() { | 710 | fn main() { |
726 | let test_struct = test_mod::TestStruct {}; | 711 | let test_struct = test_mod::TestStruct {}; |
727 | test_struct.test_meth$0od() | 712 | test_struct.test_meth$0od() |
728 | } | 713 | } |
729 | ", | 714 | "#, |
730 | r" | 715 | r#" |
731 | mod test_mod { | 716 | mod test_mod { |
732 | pub trait TestTrait { | 717 | pub trait TestTrait { |
733 | fn test_method(&self); | 718 | fn test_method(&self); |
734 | } | 719 | } |
735 | pub struct TestStruct {} | 720 | pub struct TestStruct {} |
736 | impl TestTrait for TestStruct { | 721 | impl TestTrait for TestStruct { |
737 | fn test_method(&self) {} | 722 | fn test_method(&self) {} |
738 | } | 723 | } |
739 | } | 724 | } |
740 | 725 | ||
741 | fn main() { | 726 | fn main() { |
742 | let test_struct = test_mod::TestStruct {}; | 727 | let test_struct = test_mod::TestStruct {}; |
743 | test_mod::TestTrait::test_method(&test_struct) | 728 | test_mod::TestTrait::test_method(&test_struct) |
744 | } | 729 | } |
745 | ", | 730 | "#, |
746 | ); | 731 | ); |
747 | } | 732 | } |
748 | 733 | ||
@@ -750,38 +735,38 @@ fn main() { | |||
750 | fn trait_method_multi_params() { | 735 | fn trait_method_multi_params() { |
751 | check_assist( | 736 | check_assist( |
752 | qualify_path, | 737 | qualify_path, |
753 | r" | 738 | r#" |
754 | mod test_mod { | 739 | mod test_mod { |
755 | pub trait TestTrait { | 740 | pub trait TestTrait { |
756 | fn test_method(&self, test: i32); | 741 | fn test_method(&self, test: i32); |
757 | } | 742 | } |
758 | pub struct TestStruct {} | 743 | pub struct TestStruct {} |
759 | impl TestTrait for TestStruct { | 744 | impl TestTrait for TestStruct { |
760 | fn test_method(&self, test: i32) {} | 745 | fn test_method(&self, test: i32) {} |
761 | } | 746 | } |
762 | } | 747 | } |
763 | 748 | ||
764 | fn main() { | 749 | fn main() { |
765 | let test_struct = test_mod::TestStruct {}; | 750 | let test_struct = test_mod::TestStruct {}; |
766 | test_struct.test_meth$0od(42) | 751 | test_struct.test_meth$0od(42) |
767 | } | 752 | } |
768 | ", | 753 | "#, |
769 | r" | 754 | r#" |
770 | mod test_mod { | 755 | mod test_mod { |
771 | pub trait TestTrait { | 756 | pub trait TestTrait { |
772 | fn test_method(&self, test: i32); | 757 | fn test_method(&self, test: i32); |
773 | } | 758 | } |
774 | pub struct TestStruct {} | 759 | pub struct TestStruct {} |
775 | impl TestTrait for TestStruct { | 760 | impl TestTrait for TestStruct { |
776 | fn test_method(&self, test: i32) {} | 761 | fn test_method(&self, test: i32) {} |
777 | } | 762 | } |
778 | } | 763 | } |
779 | 764 | ||
780 | fn main() { | 765 | fn main() { |
781 | let test_struct = test_mod::TestStruct {}; | 766 | let test_struct = test_mod::TestStruct {}; |
782 | test_mod::TestTrait::test_method(&test_struct, 42) | 767 | test_mod::TestTrait::test_method(&test_struct, 42) |
783 | } | 768 | } |
784 | ", | 769 | "#, |
785 | ); | 770 | ); |
786 | } | 771 | } |
787 | 772 | ||
@@ -789,38 +774,38 @@ fn main() { | |||
789 | fn trait_method_consume() { | 774 | fn trait_method_consume() { |
790 | check_assist( | 775 | check_assist( |
791 | qualify_path, | 776 | qualify_path, |
792 | r" | 777 | r#" |
793 | mod test_mod { | 778 | mod test_mod { |
794 | pub trait TestTrait { | 779 | pub trait TestTrait { |
795 | fn test_method(self); | 780 | fn test_method(self); |
796 | } | 781 | } |
797 | pub struct TestStruct {} | 782 | pub struct TestStruct {} |
798 | impl TestTrait for TestStruct { | 783 | impl TestTrait for TestStruct { |
799 | fn test_method(self) {} | 784 | fn test_method(self) {} |
800 | } | 785 | } |
801 | } | 786 | } |
802 | 787 | ||
803 | fn main() { | 788 | fn main() { |
804 | let test_struct = test_mod::TestStruct {}; | 789 | let test_struct = test_mod::TestStruct {}; |
805 | test_struct.test_meth$0od() | 790 | test_struct.test_meth$0od() |
806 | } | 791 | } |
807 | ", | 792 | "#, |
808 | r" | 793 | r#" |
809 | mod test_mod { | 794 | mod test_mod { |
810 | pub trait TestTrait { | 795 | pub trait TestTrait { |
811 | fn test_method(self); | 796 | fn test_method(self); |
812 | } | 797 | } |
813 | pub struct TestStruct {} | 798 | pub struct TestStruct {} |
814 | impl TestTrait for TestStruct { | 799 | impl TestTrait for TestStruct { |
815 | fn test_method(self) {} | 800 | fn test_method(self) {} |
816 | } | 801 | } |
817 | } | 802 | } |
818 | 803 | ||
819 | fn main() { | 804 | fn main() { |
820 | let test_struct = test_mod::TestStruct {}; | 805 | let test_struct = test_mod::TestStruct {}; |
821 | test_mod::TestTrait::test_method(test_struct) | 806 | test_mod::TestTrait::test_method(test_struct) |
822 | } | 807 | } |
823 | ", | 808 | "#, |
824 | ); | 809 | ); |
825 | } | 810 | } |
826 | 811 | ||
@@ -828,29 +813,29 @@ fn main() { | |||
828 | fn trait_method_cross_crate() { | 813 | fn trait_method_cross_crate() { |
829 | check_assist( | 814 | check_assist( |
830 | qualify_path, | 815 | qualify_path, |
831 | r" | 816 | r#" |
832 | //- /main.rs crate:main deps:dep | 817 | //- /main.rs crate:main deps:dep |
833 | fn main() { | 818 | fn main() { |
834 | let test_struct = dep::test_mod::TestStruct {}; | 819 | let test_struct = dep::test_mod::TestStruct {}; |
835 | test_struct.test_meth$0od() | 820 | test_struct.test_meth$0od() |
836 | } | 821 | } |
837 | //- /dep.rs crate:dep | 822 | //- /dep.rs crate:dep |
838 | pub mod test_mod { | 823 | pub mod test_mod { |
839 | pub trait TestTrait { | 824 | pub trait TestTrait { |
840 | fn test_method(&self); | 825 | fn test_method(&self); |
841 | } | 826 | } |
842 | pub struct TestStruct {} | 827 | pub struct TestStruct {} |
843 | impl TestTrait for TestStruct { | 828 | impl TestTrait for TestStruct { |
844 | fn test_method(&self) {} | 829 | fn test_method(&self) {} |
845 | } | 830 | } |
846 | } | 831 | } |
847 | ", | 832 | "#, |
848 | r" | 833 | r#" |
849 | fn main() { | 834 | fn main() { |
850 | let test_struct = dep::test_mod::TestStruct {}; | 835 | let test_struct = dep::test_mod::TestStruct {}; |
851 | dep::test_mod::TestTrait::test_method(&test_struct) | 836 | dep::test_mod::TestTrait::test_method(&test_struct) |
852 | } | 837 | } |
853 | ", | 838 | "#, |
854 | ); | 839 | ); |
855 | } | 840 | } |
856 | 841 | ||
@@ -858,27 +843,27 @@ fn main() { | |||
858 | fn assoc_fn_cross_crate() { | 843 | fn assoc_fn_cross_crate() { |
859 | check_assist( | 844 | check_assist( |
860 | qualify_path, | 845 | qualify_path, |
861 | r" | 846 | r#" |
862 | //- /main.rs crate:main deps:dep | 847 | //- /main.rs crate:main deps:dep |
863 | fn main() { | 848 | fn main() { |
864 | dep::test_mod::TestStruct::test_func$0tion | 849 | dep::test_mod::TestStruct::test_func$0tion |
865 | } | 850 | } |
866 | //- /dep.rs crate:dep | 851 | //- /dep.rs crate:dep |
867 | pub mod test_mod { | 852 | pub mod test_mod { |
868 | pub trait TestTrait { | 853 | pub trait TestTrait { |
869 | fn test_function(); | 854 | fn test_function(); |
870 | } | 855 | } |
871 | pub struct TestStruct {} | 856 | pub struct TestStruct {} |
872 | impl TestTrait for TestStruct { | 857 | impl TestTrait for TestStruct { |
873 | fn test_function() {} | 858 | fn test_function() {} |
874 | } | 859 | } |
875 | } | 860 | } |
876 | ", | 861 | "#, |
877 | r" | 862 | r#" |
878 | fn main() { | 863 | fn main() { |
879 | <dep::test_mod::TestStruct as dep::test_mod::TestTrait>::test_function | 864 | <dep::test_mod::TestStruct as dep::test_mod::TestTrait>::test_function |
880 | } | 865 | } |
881 | ", | 866 | "#, |
882 | ); | 867 | ); |
883 | } | 868 | } |
884 | 869 | ||
@@ -886,27 +871,27 @@ fn main() { | |||
886 | fn assoc_const_cross_crate() { | 871 | fn assoc_const_cross_crate() { |
887 | check_assist( | 872 | check_assist( |
888 | qualify_path, | 873 | qualify_path, |
889 | r" | 874 | r#" |
890 | //- /main.rs crate:main deps:dep | 875 | //- /main.rs crate:main deps:dep |
891 | fn main() { | 876 | fn main() { |
892 | dep::test_mod::TestStruct::CONST$0 | 877 | dep::test_mod::TestStruct::CONST$0 |
893 | } | 878 | } |
894 | //- /dep.rs crate:dep | 879 | //- /dep.rs crate:dep |
895 | pub mod test_mod { | 880 | pub mod test_mod { |
896 | pub trait TestTrait { | 881 | pub trait TestTrait { |
897 | const CONST: bool; | 882 | const CONST: bool; |
898 | } | 883 | } |
899 | pub struct TestStruct {} | 884 | pub struct TestStruct {} |
900 | impl TestTrait for TestStruct { | 885 | impl TestTrait for TestStruct { |
901 | const CONST: bool = true; | 886 | const CONST: bool = true; |
902 | } | 887 | } |
903 | } | 888 | } |
904 | ", | 889 | "#, |
905 | r" | 890 | r#" |
906 | fn main() { | 891 | fn main() { |
907 | <dep::test_mod::TestStruct as dep::test_mod::TestTrait>::CONST | 892 | <dep::test_mod::TestStruct as dep::test_mod::TestTrait>::CONST |
908 | } | 893 | } |
909 | ", | 894 | "#, |
910 | ); | 895 | ); |
911 | } | 896 | } |
912 | 897 | ||
@@ -914,23 +899,23 @@ fn main() { | |||
914 | fn assoc_fn_as_method_cross_crate() { | 899 | fn assoc_fn_as_method_cross_crate() { |
915 | check_assist_not_applicable( | 900 | check_assist_not_applicable( |
916 | qualify_path, | 901 | qualify_path, |
917 | r" | 902 | r#" |
918 | //- /main.rs crate:main deps:dep | 903 | //- /main.rs crate:main deps:dep |
919 | fn main() { | 904 | fn main() { |
920 | let test_struct = dep::test_mod::TestStruct {}; | 905 | let test_struct = dep::test_mod::TestStruct {}; |
921 | test_struct.test_func$0tion() | 906 | test_struct.test_func$0tion() |
922 | } | 907 | } |
923 | //- /dep.rs crate:dep | 908 | //- /dep.rs crate:dep |
924 | pub mod test_mod { | 909 | pub mod test_mod { |
925 | pub trait TestTrait { | 910 | pub trait TestTrait { |
926 | fn test_function(); | 911 | fn test_function(); |
927 | } | 912 | } |
928 | pub struct TestStruct {} | 913 | pub struct TestStruct {} |
929 | impl TestTrait for TestStruct { | 914 | impl TestTrait for TestStruct { |
930 | fn test_function() {} | 915 | fn test_function() {} |
931 | } | 916 | } |
932 | } | 917 | } |
933 | ", | 918 | "#, |
934 | ); | 919 | ); |
935 | } | 920 | } |
936 | 921 | ||
@@ -938,23 +923,23 @@ fn main() { | |||
938 | fn private_trait_cross_crate() { | 923 | fn private_trait_cross_crate() { |
939 | check_assist_not_applicable( | 924 | check_assist_not_applicable( |
940 | qualify_path, | 925 | qualify_path, |
941 | r" | 926 | r#" |
942 | //- /main.rs crate:main deps:dep | 927 | //- /main.rs crate:main deps:dep |
943 | fn main() { | 928 | fn main() { |
944 | let test_struct = dep::test_mod::TestStruct {}; | 929 | let test_struct = dep::test_mod::TestStruct {}; |
945 | test_struct.test_meth$0od() | 930 | test_struct.test_meth$0od() |
946 | } | 931 | } |
947 | //- /dep.rs crate:dep | 932 | //- /dep.rs crate:dep |
948 | pub mod test_mod { | 933 | pub mod test_mod { |
949 | trait TestTrait { | 934 | trait TestTrait { |
950 | fn test_method(&self); | 935 | fn test_method(&self); |
951 | } | 936 | } |
952 | pub struct TestStruct {} | 937 | pub struct TestStruct {} |
953 | impl TestTrait for TestStruct { | 938 | impl TestTrait for TestStruct { |
954 | fn test_method(&self) {} | 939 | fn test_method(&self) {} |
955 | } | 940 | } |
956 | } | 941 | } |
957 | ", | 942 | "#, |
958 | ); | 943 | ); |
959 | } | 944 | } |
960 | 945 | ||
@@ -962,32 +947,32 @@ fn main() { | |||
962 | fn not_applicable_for_imported_trait_for_method() { | 947 | fn not_applicable_for_imported_trait_for_method() { |
963 | check_assist_not_applicable( | 948 | check_assist_not_applicable( |
964 | qualify_path, | 949 | qualify_path, |
965 | r" | 950 | r#" |
966 | mod test_mod { | 951 | mod test_mod { |
967 | pub trait TestTrait { | 952 | pub trait TestTrait { |
968 | fn test_method(&self); | 953 | fn test_method(&self); |
969 | } | 954 | } |
970 | pub trait TestTrait2 { | 955 | pub trait TestTrait2 { |
971 | fn test_method(&self); | 956 | fn test_method(&self); |
972 | } | 957 | } |
973 | pub enum TestEnum { | 958 | pub enum TestEnum { |
974 | One, | 959 | One, |
975 | Two, | 960 | Two, |
976 | } | 961 | } |
977 | impl TestTrait2 for TestEnum { | 962 | impl TestTrait2 for TestEnum { |
978 | fn test_method(&self) {} | 963 | fn test_method(&self) {} |
979 | } | 964 | } |
980 | impl TestTrait for TestEnum { | 965 | impl TestTrait for TestEnum { |
981 | fn test_method(&self) {} | 966 | fn test_method(&self) {} |
982 | } | 967 | } |
983 | } | 968 | } |
984 | 969 | ||
985 | use test_mod::TestTrait2; | 970 | use test_mod::TestTrait2; |
986 | fn main() { | 971 | fn main() { |
987 | let one = test_mod::TestEnum::One; | 972 | let one = test_mod::TestEnum::One; |
988 | one.test$0_method(); | 973 | one.test$0_method(); |
989 | } | 974 | } |
990 | ", | 975 | "#, |
991 | ) | 976 | ) |
992 | } | 977 | } |
993 | 978 | ||
@@ -1114,7 +1099,7 @@ fn main() {} | |||
1114 | fn keep_generic_annotations_leading_colon() { | 1099 | fn keep_generic_annotations_leading_colon() { |
1115 | check_assist( | 1100 | check_assist( |
1116 | qualify_path, | 1101 | qualify_path, |
1117 | r" | 1102 | r#" |
1118 | //- /lib.rs crate:dep | 1103 | //- /lib.rs crate:dep |
1119 | pub mod generic { pub struct Thing<'a, T>(&'a T); } | 1104 | pub mod generic { pub struct Thing<'a, T>(&'a T); } |
1120 | 1105 | ||
@@ -1122,7 +1107,7 @@ pub mod generic { pub struct Thing<'a, T>(&'a T); } | |||
1122 | fn foo() -> Thin$0g::<'static, ()> {} | 1107 | fn foo() -> Thin$0g::<'static, ()> {} |
1123 | 1108 | ||
1124 | fn main() {} | 1109 | fn main() {} |
1125 | ", | 1110 | "#, |
1126 | r" | 1111 | r" |
1127 | fn foo() -> dep::generic::Thing::<'static, ()> {} | 1112 | fn foo() -> dep::generic::Thing::<'static, ()> {} |
1128 | 1113 | ||
@@ -1135,30 +1120,30 @@ fn main() {} | |||
1135 | fn associated_struct_const_generic() { | 1120 | fn associated_struct_const_generic() { |
1136 | check_assist( | 1121 | check_assist( |
1137 | qualify_path, | 1122 | qualify_path, |
1138 | r" | 1123 | r#" |
1139 | mod test_mod { | 1124 | mod test_mod { |
1140 | pub struct TestStruct<T> {} | 1125 | pub struct TestStruct<T> {} |
1141 | impl<T> TestStruct<T> { | 1126 | impl<T> TestStruct<T> { |
1142 | const TEST_CONST: u8 = 42; | 1127 | const TEST_CONST: u8 = 42; |
1143 | } | 1128 | } |
1144 | } | 1129 | } |
1145 | 1130 | ||
1146 | fn main() { | 1131 | fn main() { |
1147 | TestStruct::<()>::TEST_CONST$0 | 1132 | TestStruct::<()>::TEST_CONST$0 |
1148 | } | 1133 | } |
1149 | ", | 1134 | "#, |
1150 | r" | 1135 | r#" |
1151 | mod test_mod { | 1136 | mod test_mod { |
1152 | pub struct TestStruct<T> {} | 1137 | pub struct TestStruct<T> {} |
1153 | impl<T> TestStruct<T> { | 1138 | impl<T> TestStruct<T> { |
1154 | const TEST_CONST: u8 = 42; | 1139 | const TEST_CONST: u8 = 42; |
1155 | } | 1140 | } |
1156 | } | 1141 | } |
1157 | 1142 | ||
1158 | fn main() { | 1143 | fn main() { |
1159 | test_mod::TestStruct::<()>::TEST_CONST | 1144 | test_mod::TestStruct::<()>::TEST_CONST |
1160 | } | 1145 | } |
1161 | ", | 1146 | "#, |
1162 | ); | 1147 | ); |
1163 | } | 1148 | } |
1164 | 1149 | ||
@@ -1166,36 +1151,36 @@ fn main() {} | |||
1166 | fn associated_trait_const_generic() { | 1151 | fn associated_trait_const_generic() { |
1167 | check_assist( | 1152 | check_assist( |
1168 | qualify_path, | 1153 | qualify_path, |
1169 | r" | 1154 | r#" |
1170 | mod test_mod { | 1155 | mod test_mod { |
1171 | pub trait TestTrait { | 1156 | pub trait TestTrait { |
1172 | const TEST_CONST: u8; | 1157 | const TEST_CONST: u8; |
1173 | } | 1158 | } |
1174 | pub struct TestStruct<T> {} | 1159 | pub struct TestStruct<T> {} |
1175 | impl<T> TestTrait for TestStruct<T> { | 1160 | impl<T> TestTrait for TestStruct<T> { |
1176 | const TEST_CONST: u8 = 42; | 1161 | const TEST_CONST: u8 = 42; |
1177 | } | 1162 | } |
1178 | } | 1163 | } |
1179 | 1164 | ||
1180 | fn main() { | 1165 | fn main() { |
1181 | test_mod::TestStruct::<()>::TEST_CONST$0 | 1166 | test_mod::TestStruct::<()>::TEST_CONST$0 |
1182 | } | 1167 | } |
1183 | ", | 1168 | "#, |
1184 | r" | 1169 | r#" |
1185 | mod test_mod { | 1170 | mod test_mod { |
1186 | pub trait TestTrait { | 1171 | pub trait TestTrait { |
1187 | const TEST_CONST: u8; | 1172 | const TEST_CONST: u8; |
1188 | } | 1173 | } |
1189 | pub struct TestStruct<T> {} | 1174 | pub struct TestStruct<T> {} |
1190 | impl<T> TestTrait for TestStruct<T> { | 1175 | impl<T> TestTrait for TestStruct<T> { |
1191 | const TEST_CONST: u8 = 42; | 1176 | const TEST_CONST: u8 = 42; |
1192 | } | 1177 | } |
1193 | } | 1178 | } |
1194 | 1179 | ||
1195 | fn main() { | 1180 | fn main() { |
1196 | <test_mod::TestStruct::<()> as test_mod::TestTrait>::TEST_CONST | 1181 | <test_mod::TestStruct::<()> as test_mod::TestTrait>::TEST_CONST |
1197 | } | 1182 | } |
1198 | ", | 1183 | "#, |
1199 | ); | 1184 | ); |
1200 | } | 1185 | } |
1201 | 1186 | ||
@@ -1203,38 +1188,38 @@ fn main() {} | |||
1203 | fn trait_method_generic() { | 1188 | fn trait_method_generic() { |
1204 | check_assist( | 1189 | check_assist( |
1205 | qualify_path, | 1190 | qualify_path, |
1206 | r" | 1191 | r#" |
1207 | mod test_mod { | 1192 | mod test_mod { |
1208 | pub trait TestTrait { | 1193 | pub trait TestTrait { |
1209 | fn test_method<T>(&self); | 1194 | fn test_method<T>(&self); |
1210 | } | 1195 | } |
1211 | pub struct TestStruct {} | 1196 | pub struct TestStruct {} |
1212 | impl TestTrait for TestStruct { | 1197 | impl TestTrait for TestStruct { |
1213 | fn test_method<T>(&self) {} | 1198 | fn test_method<T>(&self) {} |
1214 | } | 1199 | } |
1215 | } | 1200 | } |
1216 | 1201 | ||
1217 | fn main() { | 1202 | fn main() { |
1218 | let test_struct = test_mod::TestStruct {}; | 1203 | let test_struct = test_mod::TestStruct {}; |
1219 | test_struct.test_meth$0od::<()>() | 1204 | test_struct.test_meth$0od::<()>() |
1220 | } | 1205 | } |
1221 | ", | 1206 | "#, |
1222 | r" | 1207 | r#" |
1223 | mod test_mod { | 1208 | mod test_mod { |
1224 | pub trait TestTrait { | 1209 | pub trait TestTrait { |
1225 | fn test_method<T>(&self); | 1210 | fn test_method<T>(&self); |
1226 | } | 1211 | } |
1227 | pub struct TestStruct {} | 1212 | pub struct TestStruct {} |
1228 | impl TestTrait for TestStruct { | 1213 | impl TestTrait for TestStruct { |
1229 | fn test_method<T>(&self) {} | 1214 | fn test_method<T>(&self) {} |
1230 | } | 1215 | } |
1231 | } | 1216 | } |
1232 | 1217 | ||
1233 | fn main() { | 1218 | fn main() { |
1234 | let test_struct = test_mod::TestStruct {}; | 1219 | let test_struct = test_mod::TestStruct {}; |
1235 | test_mod::TestTrait::test_method::<()>(&test_struct) | 1220 | test_mod::TestTrait::test_method::<()>(&test_struct) |
1236 | } | 1221 | } |
1237 | ", | 1222 | "#, |
1238 | ); | 1223 | ); |
1239 | } | 1224 | } |
1240 | } | 1225 | } |
diff --git a/crates/ide_assists/src/handlers/replace_impl_trait_with_generic.rs b/crates/ide_assists/src/handlers/replace_impl_trait_with_generic.rs index 540a905cc..a2af2035f 100644 --- a/crates/ide_assists/src/handlers/replace_impl_trait_with_generic.rs +++ b/crates/ide_assists/src/handlers/replace_impl_trait_with_generic.rs | |||
@@ -105,12 +105,13 @@ fn foo<B: Bar | |||
105 | } | 105 | } |
106 | 106 | ||
107 | #[test] | 107 | #[test] |
108 | #[ignore = "This case is very rare but there is no simple solutions to fix it."] | ||
109 | fn replace_impl_trait_with_exist_generic_letter() { | 108 | fn replace_impl_trait_with_exist_generic_letter() { |
109 | // FIXME: This is wrong, we should pick a different name if the one we | ||
110 | // want is already bound. | ||
110 | check_assist( | 111 | check_assist( |
111 | replace_impl_trait_with_generic, | 112 | replace_impl_trait_with_generic, |
112 | r#"fn foo<B>(bar: $0impl Bar) {}"#, | 113 | r#"fn foo<B>(bar: $0impl Bar) {}"#, |
113 | r#"fn foo<B, C: Bar>(bar: C) {}"#, | 114 | r#"fn foo<B, B: Bar>(bar: B) {}"#, |
114 | ); | 115 | ); |
115 | } | 116 | } |
116 | 117 | ||
diff --git a/crates/ide_assists/src/lib.rs b/crates/ide_assists/src/lib.rs index 331a6df2b..fa378a622 100644 --- a/crates/ide_assists/src/lib.rs +++ b/crates/ide_assists/src/lib.rs | |||
@@ -17,156 +17,31 @@ mod tests; | |||
17 | pub mod utils; | 17 | pub mod utils; |
18 | pub mod path_transform; | 18 | pub mod path_transform; |
19 | 19 | ||
20 | use std::str::FromStr; | ||
21 | |||
22 | use hir::Semantics; | 20 | use hir::Semantics; |
23 | use ide_db::{base_db::FileRange, label::Label, source_change::SourceChange, RootDatabase}; | 21 | use ide_db::{base_db::FileRange, RootDatabase}; |
24 | use syntax::TextRange; | 22 | use syntax::TextRange; |
25 | 23 | ||
26 | pub(crate) use crate::assist_context::{AssistContext, Assists}; | 24 | pub(crate) use crate::assist_context::{AssistContext, Assists}; |
27 | 25 | ||
28 | pub use assist_config::AssistConfig; | 26 | pub use assist_config::AssistConfig; |
29 | 27 | pub use ide_db::assists::{ | |
30 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] | 28 | Assist, AssistId, AssistKind, AssistResolveStrategy, GroupLabel, SingleResolve, |
31 | pub enum AssistKind { | 29 | }; |
32 | // FIXME: does the None variant make sense? Probably not. | 30 | |
33 | None, | 31 | /// Return all the assists applicable at the given position. |
34 | 32 | pub fn assists( | |
35 | QuickFix, | 33 | db: &RootDatabase, |
36 | Generate, | 34 | config: &AssistConfig, |
37 | Refactor, | 35 | resolve: AssistResolveStrategy, |
38 | RefactorExtract, | 36 | range: FileRange, |
39 | RefactorInline, | 37 | ) -> Vec<Assist> { |
40 | RefactorRewrite, | 38 | let sema = Semantics::new(db); |
41 | } | 39 | let ctx = AssistContext::new(sema, config, range); |
42 | 40 | let mut acc = Assists::new(&ctx, resolve); | |
43 | impl AssistKind { | 41 | handlers::all().iter().for_each(|handler| { |
44 | pub fn contains(self, other: AssistKind) -> bool { | 42 | handler(&mut acc, &ctx); |
45 | if self == other { | 43 | }); |
46 | return true; | 44 | acc.finish() |
47 | } | ||
48 | |||
49 | match self { | ||
50 | AssistKind::None | AssistKind::Generate => true, | ||
51 | AssistKind::Refactor => match other { | ||
52 | AssistKind::RefactorExtract | ||
53 | | AssistKind::RefactorInline | ||
54 | | AssistKind::RefactorRewrite => true, | ||
55 | _ => false, | ||
56 | }, | ||
57 | _ => false, | ||
58 | } | ||
59 | } | ||
60 | |||
61 | pub fn name(&self) -> &str { | ||
62 | match self { | ||
63 | AssistKind::None => "None", | ||
64 | AssistKind::QuickFix => "QuickFix", | ||
65 | AssistKind::Generate => "Generate", | ||
66 | AssistKind::Refactor => "Refactor", | ||
67 | AssistKind::RefactorExtract => "RefactorExtract", | ||
68 | AssistKind::RefactorInline => "RefactorInline", | ||
69 | AssistKind::RefactorRewrite => "RefactorRewrite", | ||
70 | } | ||
71 | } | ||
72 | } | ||
73 | |||
74 | impl FromStr for AssistKind { | ||
75 | type Err = String; | ||
76 | |||
77 | fn from_str(s: &str) -> Result<Self, Self::Err> { | ||
78 | match s { | ||
79 | "None" => Ok(AssistKind::None), | ||
80 | "QuickFix" => Ok(AssistKind::QuickFix), | ||
81 | "Generate" => Ok(AssistKind::Generate), | ||
82 | "Refactor" => Ok(AssistKind::Refactor), | ||
83 | "RefactorExtract" => Ok(AssistKind::RefactorExtract), | ||
84 | "RefactorInline" => Ok(AssistKind::RefactorInline), | ||
85 | "RefactorRewrite" => Ok(AssistKind::RefactorRewrite), | ||
86 | unknown => Err(format!("Unknown AssistKind: '{}'", unknown)), | ||
87 | } | ||
88 | } | ||
89 | } | ||
90 | |||
91 | /// Unique identifier of the assist, should not be shown to the user | ||
92 | /// directly. | ||
93 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] | ||
94 | pub struct AssistId(pub &'static str, pub AssistKind); | ||
95 | |||
96 | /// A way to control how many asssist to resolve during the assist resolution. | ||
97 | /// When an assist is resolved, its edits are calculated that might be costly to always do by default. | ||
98 | #[derive(Debug)] | ||
99 | pub enum AssistResolveStrategy { | ||
100 | /// No assists should be resolved. | ||
101 | None, | ||
102 | /// All assists should be resolved. | ||
103 | All, | ||
104 | /// Only a certain assist should be resolved. | ||
105 | Single(SingleResolve), | ||
106 | } | ||
107 | |||
108 | /// Hold the [`AssistId`] data of a certain assist to resolve. | ||
109 | /// The original id object cannot be used due to a `'static` lifetime | ||
110 | /// and the requirement to construct this struct dynamically during the resolve handling. | ||
111 | #[derive(Debug)] | ||
112 | pub struct SingleResolve { | ||
113 | /// The id of the assist. | ||
114 | pub assist_id: String, | ||
115 | // The kind of the assist. | ||
116 | pub assist_kind: AssistKind, | ||
117 | } | ||
118 | |||
119 | impl AssistResolveStrategy { | ||
120 | pub fn should_resolve(&self, id: &AssistId) -> bool { | ||
121 | match self { | ||
122 | AssistResolveStrategy::None => false, | ||
123 | AssistResolveStrategy::All => true, | ||
124 | AssistResolveStrategy::Single(single_resolve) => { | ||
125 | single_resolve.assist_id == id.0 && single_resolve.assist_kind == id.1 | ||
126 | } | ||
127 | } | ||
128 | } | ||
129 | } | ||
130 | |||
131 | #[derive(Clone, Debug)] | ||
132 | pub struct GroupLabel(pub String); | ||
133 | |||
134 | #[derive(Debug, Clone)] | ||
135 | pub struct Assist { | ||
136 | pub id: AssistId, | ||
137 | /// Short description of the assist, as shown in the UI. | ||
138 | pub label: Label, | ||
139 | pub group: Option<GroupLabel>, | ||
140 | /// Target ranges are used to sort assists: the smaller the target range, | ||
141 | /// the more specific assist is, and so it should be sorted first. | ||
142 | pub target: TextRange, | ||
143 | /// Computing source change sometimes is much more costly then computing the | ||
144 | /// other fields. Additionally, the actual change is not required to show | ||
145 | /// the lightbulb UI, it only is needed when the user tries to apply an | ||
146 | /// assist. So, we compute it lazily: the API allow requesting assists with | ||
147 | /// or without source change. We could (and in fact, used to) distinguish | ||
148 | /// between resolved and unresolved assists at the type level, but this is | ||
149 | /// cumbersome, especially if you want to embed an assist into another data | ||
150 | /// structure, such as a diagnostic. | ||
151 | pub source_change: Option<SourceChange>, | ||
152 | } | ||
153 | |||
154 | impl Assist { | ||
155 | /// Return all the assists applicable at the given position. | ||
156 | pub fn get( | ||
157 | db: &RootDatabase, | ||
158 | config: &AssistConfig, | ||
159 | resolve: AssistResolveStrategy, | ||
160 | range: FileRange, | ||
161 | ) -> Vec<Assist> { | ||
162 | let sema = Semantics::new(db); | ||
163 | let ctx = AssistContext::new(sema, config, range); | ||
164 | let mut acc = Assists::new(&ctx, resolve); | ||
165 | handlers::all().iter().for_each(|handler| { | ||
166 | handler(&mut acc, &ctx); | ||
167 | }); | ||
168 | acc.finish() | ||
169 | } | ||
170 | } | 45 | } |
171 | 46 | ||
172 | mod handlers { | 47 | mod handlers { |
diff --git a/crates/ide_assists/src/tests.rs b/crates/ide_assists/src/tests.rs index bdf9cb71c..60cecd94c 100644 --- a/crates/ide_assists/src/tests.rs +++ b/crates/ide_assists/src/tests.rs | |||
@@ -16,8 +16,8 @@ use syntax::TextRange; | |||
16 | use test_utils::{assert_eq_text, extract_offset}; | 16 | use test_utils::{assert_eq_text, extract_offset}; |
17 | 17 | ||
18 | use crate::{ | 18 | use crate::{ |
19 | handlers::Handler, Assist, AssistConfig, AssistContext, AssistKind, AssistResolveStrategy, | 19 | assists, handlers::Handler, Assist, AssistConfig, AssistContext, AssistKind, |
20 | Assists, SingleResolve, | 20 | AssistResolveStrategy, Assists, SingleResolve, |
21 | }; | 21 | }; |
22 | 22 | ||
23 | pub(crate) const TEST_CONFIG: AssistConfig = AssistConfig { | 23 | pub(crate) const TEST_CONFIG: AssistConfig = AssistConfig { |
@@ -78,14 +78,14 @@ fn check_doc_test(assist_id: &str, before: &str, after: &str) { | |||
78 | let before = db.file_text(file_id).to_string(); | 78 | let before = db.file_text(file_id).to_string(); |
79 | let frange = FileRange { file_id, range: selection.into() }; | 79 | let frange = FileRange { file_id, range: selection.into() }; |
80 | 80 | ||
81 | let assist = Assist::get(&db, &TEST_CONFIG, AssistResolveStrategy::All, frange) | 81 | let assist = assists(&db, &TEST_CONFIG, AssistResolveStrategy::All, frange) |
82 | .into_iter() | 82 | .into_iter() |
83 | .find(|assist| assist.id.0 == assist_id) | 83 | .find(|assist| assist.id.0 == assist_id) |
84 | .unwrap_or_else(|| { | 84 | .unwrap_or_else(|| { |
85 | panic!( | 85 | panic!( |
86 | "\n\nAssist is not applicable: {}\nAvailable assists: {}", | 86 | "\n\nAssist is not applicable: {}\nAvailable assists: {}", |
87 | assist_id, | 87 | assist_id, |
88 | Assist::get(&db, &TEST_CONFIG, AssistResolveStrategy::None, frange) | 88 | assists(&db, &TEST_CONFIG, AssistResolveStrategy::None, frange) |
89 | .into_iter() | 89 | .into_iter() |
90 | .map(|assist| assist.id.0) | 90 | .map(|assist| assist.id.0) |
91 | .collect::<Vec<_>>() | 91 | .collect::<Vec<_>>() |
@@ -210,7 +210,7 @@ fn assist_order_field_struct() { | |||
210 | let (before_cursor_pos, before) = extract_offset(before); | 210 | let (before_cursor_pos, before) = extract_offset(before); |
211 | let (db, file_id) = with_single_file(&before); | 211 | let (db, file_id) = with_single_file(&before); |
212 | let frange = FileRange { file_id, range: TextRange::empty(before_cursor_pos) }; | 212 | let frange = FileRange { file_id, range: TextRange::empty(before_cursor_pos) }; |
213 | let assists = Assist::get(&db, &TEST_CONFIG, AssistResolveStrategy::None, frange); | 213 | let assists = assists(&db, &TEST_CONFIG, AssistResolveStrategy::None, frange); |
214 | let mut assists = assists.iter(); | 214 | let mut assists = assists.iter(); |
215 | 215 | ||
216 | assert_eq!(assists.next().expect("expected assist").label, "Change visibility to pub(crate)"); | 216 | assert_eq!(assists.next().expect("expected assist").label, "Change visibility to pub(crate)"); |
@@ -235,7 +235,7 @@ pub fn test_some_range(a: int) -> bool { | |||
235 | "#, | 235 | "#, |
236 | ); | 236 | ); |
237 | 237 | ||
238 | let assists = Assist::get(&db, &TEST_CONFIG, AssistResolveStrategy::None, frange); | 238 | let assists = assists(&db, &TEST_CONFIG, AssistResolveStrategy::None, frange); |
239 | let expected = labels(&assists); | 239 | let expected = labels(&assists); |
240 | 240 | ||
241 | expect![[r#" | 241 | expect![[r#" |
@@ -264,7 +264,7 @@ pub fn test_some_range(a: int) -> bool { | |||
264 | let mut cfg = TEST_CONFIG; | 264 | let mut cfg = TEST_CONFIG; |
265 | cfg.allowed = Some(vec![AssistKind::Refactor]); | 265 | cfg.allowed = Some(vec![AssistKind::Refactor]); |
266 | 266 | ||
267 | let assists = Assist::get(&db, &cfg, AssistResolveStrategy::None, frange); | 267 | let assists = assists(&db, &cfg, AssistResolveStrategy::None, frange); |
268 | let expected = labels(&assists); | 268 | let expected = labels(&assists); |
269 | 269 | ||
270 | expect![[r#" | 270 | expect![[r#" |
@@ -279,7 +279,7 @@ pub fn test_some_range(a: int) -> bool { | |||
279 | { | 279 | { |
280 | let mut cfg = TEST_CONFIG; | 280 | let mut cfg = TEST_CONFIG; |
281 | cfg.allowed = Some(vec![AssistKind::RefactorExtract]); | 281 | cfg.allowed = Some(vec![AssistKind::RefactorExtract]); |
282 | let assists = Assist::get(&db, &cfg, AssistResolveStrategy::None, frange); | 282 | let assists = assists(&db, &cfg, AssistResolveStrategy::None, frange); |
283 | let expected = labels(&assists); | 283 | let expected = labels(&assists); |
284 | 284 | ||
285 | expect![[r#" | 285 | expect![[r#" |
@@ -292,7 +292,7 @@ pub fn test_some_range(a: int) -> bool { | |||
292 | { | 292 | { |
293 | let mut cfg = TEST_CONFIG; | 293 | let mut cfg = TEST_CONFIG; |
294 | cfg.allowed = Some(vec![AssistKind::QuickFix]); | 294 | cfg.allowed = Some(vec![AssistKind::QuickFix]); |
295 | let assists = Assist::get(&db, &cfg, AssistResolveStrategy::None, frange); | 295 | let assists = assists(&db, &cfg, AssistResolveStrategy::None, frange); |
296 | let expected = labels(&assists); | 296 | let expected = labels(&assists); |
297 | 297 | ||
298 | expect![[r#""#]].assert_eq(&expected); | 298 | expect![[r#""#]].assert_eq(&expected); |
@@ -317,7 +317,7 @@ pub fn test_some_range(a: int) -> bool { | |||
317 | cfg.allowed = Some(vec![AssistKind::RefactorExtract]); | 317 | cfg.allowed = Some(vec![AssistKind::RefactorExtract]); |
318 | 318 | ||
319 | { | 319 | { |
320 | let assists = Assist::get(&db, &cfg, AssistResolveStrategy::None, frange); | 320 | let assists = assists(&db, &cfg, AssistResolveStrategy::None, frange); |
321 | assert_eq!(2, assists.len()); | 321 | assert_eq!(2, assists.len()); |
322 | let mut assists = assists.into_iter(); | 322 | let mut assists = assists.into_iter(); |
323 | 323 | ||
@@ -353,7 +353,7 @@ pub fn test_some_range(a: int) -> bool { | |||
353 | } | 353 | } |
354 | 354 | ||
355 | { | 355 | { |
356 | let assists = Assist::get( | 356 | let assists = assists( |
357 | &db, | 357 | &db, |
358 | &cfg, | 358 | &cfg, |
359 | AssistResolveStrategy::Single(SingleResolve { | 359 | AssistResolveStrategy::Single(SingleResolve { |
@@ -397,7 +397,7 @@ pub fn test_some_range(a: int) -> bool { | |||
397 | } | 397 | } |
398 | 398 | ||
399 | { | 399 | { |
400 | let assists = Assist::get( | 400 | let assists = assists( |
401 | &db, | 401 | &db, |
402 | &cfg, | 402 | &cfg, |
403 | AssistResolveStrategy::Single(SingleResolve { | 403 | AssistResolveStrategy::Single(SingleResolve { |
@@ -462,7 +462,7 @@ pub fn test_some_range(a: int) -> bool { | |||
462 | } | 462 | } |
463 | 463 | ||
464 | { | 464 | { |
465 | let assists = Assist::get(&db, &cfg, AssistResolveStrategy::All, frange); | 465 | let assists = assists(&db, &cfg, AssistResolveStrategy::All, frange); |
466 | assert_eq!(2, assists.len()); | 466 | assert_eq!(2, assists.len()); |
467 | let mut assists = assists.into_iter(); | 467 | let mut assists = assists.into_iter(); |
468 | 468 | ||
diff --git a/crates/ide_completion/src/completions/attribute/derive.rs b/crates/ide_completion/src/completions/attribute/derive.rs index d526824fb..7b3133e53 100644 --- a/crates/ide_completion/src/completions/attribute/derive.rs +++ b/crates/ide_completion/src/completions/attribute/derive.rs | |||
@@ -93,57 +93,20 @@ mod tests { | |||
93 | } | 93 | } |
94 | 94 | ||
95 | #[test] | 95 | #[test] |
96 | #[ignore] // FIXME: Fixtures cant test proc-macros/derives yet as we cant specify them in fixtures | ||
97 | fn empty_derive() { | 96 | fn empty_derive() { |
98 | check( | 97 | // FIXME: Add build-in derives to fixture. |
99 | r#"#[derive($0)] struct Test;"#, | 98 | check(r#"#[derive($0)] struct Test;"#, expect![[r#""#]]); |
100 | expect![[r#" | ||
101 | at Clone | ||
102 | at Clone, Copy | ||
103 | at Debug | ||
104 | at Default | ||
105 | at Hash | ||
106 | at PartialEq | ||
107 | at PartialEq, Eq | ||
108 | at PartialEq, PartialOrd | ||
109 | at PartialEq, Eq, PartialOrd, Ord | ||
110 | "#]], | ||
111 | ); | ||
112 | } | 99 | } |
113 | 100 | ||
114 | #[test] | 101 | #[test] |
115 | #[ignore] // FIXME: Fixtures cant test proc-macros/derives yet as we cant specify them in fixtures | ||
116 | fn derive_with_input() { | 102 | fn derive_with_input() { |
117 | check( | 103 | // FIXME: Add build-in derives to fixture. |
118 | r#"#[derive(serde::Serialize, PartialEq, $0)] struct Test;"#, | 104 | check(r#"#[derive(serde::Serialize, PartialEq, $0)] struct Test;"#, expect![[r#""#]]) |
119 | expect![[r#" | ||
120 | at Clone | ||
121 | at Clone, Copy | ||
122 | at Debug | ||
123 | at Default | ||
124 | at Hash | ||
125 | at Eq | ||
126 | at PartialOrd | ||
127 | at Eq, PartialOrd, Ord | ||
128 | "#]], | ||
129 | ) | ||
130 | } | 105 | } |
131 | 106 | ||
132 | #[test] | 107 | #[test] |
133 | #[ignore] // FIXME: Fixtures cant test proc-macros/derives yet as we cant specify them in fixtures | ||
134 | fn derive_with_input2() { | 108 | fn derive_with_input2() { |
135 | check( | 109 | // FIXME: Add build-in derives to fixture. |
136 | r#"#[derive($0 serde::Serialize, PartialEq)] struct Test;"#, | 110 | check(r#"#[derive($0 serde::Serialize, PartialEq)] struct Test;"#, expect![[r#""#]]) |
137 | expect![[r#" | ||
138 | at Clone | ||
139 | at Clone, Copy | ||
140 | at Debug | ||
141 | at Default | ||
142 | at Hash | ||
143 | at Eq | ||
144 | at PartialOrd | ||
145 | at Eq, PartialOrd, Ord | ||
146 | "#]], | ||
147 | ) | ||
148 | } | 111 | } |
149 | } | 112 | } |
diff --git a/crates/ide_completion/src/completions/keyword.rs b/crates/ide_completion/src/completions/keyword.rs index ba13d3707..0fccbeccf 100644 --- a/crates/ide_completion/src/completions/keyword.rs +++ b/crates/ide_completion/src/completions/keyword.rs | |||
@@ -536,17 +536,11 @@ Some multi-line comment$0 | |||
536 | fn test_completion_await_impls_future() { | 536 | fn test_completion_await_impls_future() { |
537 | check( | 537 | check( |
538 | r#" | 538 | r#" |
539 | //- /main.rs crate:main deps:std | 539 | //- minicore: future |
540 | use std::future::*; | 540 | use core::future::*; |
541 | struct A {} | 541 | struct A {} |
542 | impl Future for A {} | 542 | impl Future for A {} |
543 | fn foo(a: A) { a.$0 } | 543 | fn foo(a: A) { a.$0 } |
544 | |||
545 | //- /std/lib.rs crate:std | ||
546 | pub mod future { | ||
547 | #[lang = "future_trait"] | ||
548 | pub trait Future {} | ||
549 | } | ||
550 | "#, | 544 | "#, |
551 | expect![[r#" | 545 | expect![[r#" |
552 | kw await expr.await | 546 | kw await expr.await |
@@ -555,20 +549,12 @@ pub mod future { | |||
555 | 549 | ||
556 | check( | 550 | check( |
557 | r#" | 551 | r#" |
558 | //- /main.rs crate:main deps:std | 552 | //- minicore: future |
559 | use std::future::*; | 553 | use std::future::*; |
560 | fn foo() { | 554 | fn foo() { |
561 | let a = async {}; | 555 | let a = async {}; |
562 | a.$0 | 556 | a.$0 |
563 | } | 557 | } |
564 | |||
565 | //- /std/lib.rs crate:std | ||
566 | pub mod future { | ||
567 | #[lang = "future_trait"] | ||
568 | pub trait Future { | ||
569 | type Output; | ||
570 | } | ||
571 | } | ||
572 | "#, | 558 | "#, |
573 | expect![[r#" | 559 | expect![[r#" |
574 | kw await expr.await | 560 | kw await expr.await |
diff --git a/crates/ide_completion/src/completions/unqualified_path.rs b/crates/ide_completion/src/completions/unqualified_path.rs index 952f052a1..f86b2d3f3 100644 --- a/crates/ide_completion/src/completions/unqualified_path.rs +++ b/crates/ide_completion/src/completions/unqualified_path.rs | |||
@@ -809,4 +809,22 @@ fn foo(_: impl Foo<B$0>) {} | |||
809 | "#]], | 809 | "#]], |
810 | ); | 810 | ); |
811 | } | 811 | } |
812 | |||
813 | #[test] | ||
814 | fn completes_assoc_types_in_trait_bound() { | ||
815 | check( | ||
816 | r#" | ||
817 | trait Foo { | ||
818 | type Bar; | ||
819 | } | ||
820 | |||
821 | fn foo<T: Foo<B$0>>(_: T) {} | ||
822 | "#, | ||
823 | expect![[r#" | ||
824 | ta Bar = type Bar; | ||
825 | tp T | ||
826 | tt Foo | ||
827 | "#]], | ||
828 | ); | ||
829 | } | ||
812 | } | 830 | } |
diff --git a/crates/ide_completion/src/render.rs b/crates/ide_completion/src/render.rs index d8ca18c73..3eb51e80b 100644 --- a/crates/ide_completion/src/render.rs +++ b/crates/ide_completion/src/render.rs | |||
@@ -1152,16 +1152,11 @@ fn main() { | |||
1152 | fn suggest_deref() { | 1152 | fn suggest_deref() { |
1153 | check_relevance( | 1153 | check_relevance( |
1154 | r#" | 1154 | r#" |
1155 | #[lang = "deref"] | 1155 | //- minicore: deref |
1156 | trait Deref { | ||
1157 | type Target; | ||
1158 | fn deref(&self) -> &Self::Target; | ||
1159 | } | ||
1160 | |||
1161 | struct S; | 1156 | struct S; |
1162 | struct T(S); | 1157 | struct T(S); |
1163 | 1158 | ||
1164 | impl Deref for T { | 1159 | impl core::ops::Deref for T { |
1165 | type Target = S; | 1160 | type Target = S; |
1166 | 1161 | ||
1167 | fn deref(&self) -> &Self::Target { | 1162 | fn deref(&self) -> &Self::Target { |
@@ -1185,8 +1180,9 @@ fn main() { | |||
1185 | st T [] | 1180 | st T [] |
1186 | st S [] | 1181 | st S [] |
1187 | fn main() [] | 1182 | fn main() [] |
1188 | tt Deref [] | ||
1189 | fn foo(…) [] | 1183 | fn foo(…) [] |
1184 | md core [] | ||
1185 | tt Sized [] | ||
1190 | "#]], | 1186 | "#]], |
1191 | ) | 1187 | ) |
1192 | } | 1188 | } |
diff --git a/crates/ide_db/src/assists.rs b/crates/ide_db/src/assists.rs new file mode 100644 index 000000000..7881d8369 --- /dev/null +++ b/crates/ide_db/src/assists.rs | |||
@@ -0,0 +1,136 @@ | |||
1 | //! This module defines the `Assist` data structure. The actual assist live in | ||
2 | //! the `ide_assists` downstream crate. We want to define the data structures in | ||
3 | //! this low-level crate though, because `ide_diagnostics` also need them | ||
4 | //! (fixits for diagnostics and assists are the same thing under the hood). We | ||
5 | //! want to compile `ide_assists` and `ide_diagnostics` in parallel though, so | ||
6 | //! we pull the common definitions upstream, to this crate. | ||
7 | |||
8 | use std::str::FromStr; | ||
9 | |||
10 | use syntax::TextRange; | ||
11 | |||
12 | use crate::{label::Label, source_change::SourceChange}; | ||
13 | |||
14 | #[derive(Debug, Clone)] | ||
15 | pub struct Assist { | ||
16 | pub id: AssistId, | ||
17 | /// Short description of the assist, as shown in the UI. | ||
18 | pub label: Label, | ||
19 | pub group: Option<GroupLabel>, | ||
20 | /// Target ranges are used to sort assists: the smaller the target range, | ||
21 | /// the more specific assist is, and so it should be sorted first. | ||
22 | pub target: TextRange, | ||
23 | /// Computing source change sometimes is much more costly then computing the | ||
24 | /// other fields. Additionally, the actual change is not required to show | ||
25 | /// the lightbulb UI, it only is needed when the user tries to apply an | ||
26 | /// assist. So, we compute it lazily: the API allow requesting assists with | ||
27 | /// or without source change. We could (and in fact, used to) distinguish | ||
28 | /// between resolved and unresolved assists at the type level, but this is | ||
29 | /// cumbersome, especially if you want to embed an assist into another data | ||
30 | /// structure, such as a diagnostic. | ||
31 | pub source_change: Option<SourceChange>, | ||
32 | } | ||
33 | |||
34 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] | ||
35 | pub enum AssistKind { | ||
36 | // FIXME: does the None variant make sense? Probably not. | ||
37 | None, | ||
38 | |||
39 | QuickFix, | ||
40 | Generate, | ||
41 | Refactor, | ||
42 | RefactorExtract, | ||
43 | RefactorInline, | ||
44 | RefactorRewrite, | ||
45 | } | ||
46 | |||
47 | impl AssistKind { | ||
48 | pub fn contains(self, other: AssistKind) -> bool { | ||
49 | if self == other { | ||
50 | return true; | ||
51 | } | ||
52 | |||
53 | match self { | ||
54 | AssistKind::None | AssistKind::Generate => true, | ||
55 | AssistKind::Refactor => match other { | ||
56 | AssistKind::RefactorExtract | ||
57 | | AssistKind::RefactorInline | ||
58 | | AssistKind::RefactorRewrite => true, | ||
59 | _ => false, | ||
60 | }, | ||
61 | _ => false, | ||
62 | } | ||
63 | } | ||
64 | |||
65 | pub fn name(&self) -> &str { | ||
66 | match self { | ||
67 | AssistKind::None => "None", | ||
68 | AssistKind::QuickFix => "QuickFix", | ||
69 | AssistKind::Generate => "Generate", | ||
70 | AssistKind::Refactor => "Refactor", | ||
71 | AssistKind::RefactorExtract => "RefactorExtract", | ||
72 | AssistKind::RefactorInline => "RefactorInline", | ||
73 | AssistKind::RefactorRewrite => "RefactorRewrite", | ||
74 | } | ||
75 | } | ||
76 | } | ||
77 | |||
78 | impl FromStr for AssistKind { | ||
79 | type Err = String; | ||
80 | |||
81 | fn from_str(s: &str) -> Result<Self, Self::Err> { | ||
82 | match s { | ||
83 | "None" => Ok(AssistKind::None), | ||
84 | "QuickFix" => Ok(AssistKind::QuickFix), | ||
85 | "Generate" => Ok(AssistKind::Generate), | ||
86 | "Refactor" => Ok(AssistKind::Refactor), | ||
87 | "RefactorExtract" => Ok(AssistKind::RefactorExtract), | ||
88 | "RefactorInline" => Ok(AssistKind::RefactorInline), | ||
89 | "RefactorRewrite" => Ok(AssistKind::RefactorRewrite), | ||
90 | unknown => Err(format!("Unknown AssistKind: '{}'", unknown)), | ||
91 | } | ||
92 | } | ||
93 | } | ||
94 | |||
95 | /// Unique identifier of the assist, should not be shown to the user | ||
96 | /// directly. | ||
97 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] | ||
98 | pub struct AssistId(pub &'static str, pub AssistKind); | ||
99 | |||
100 | /// A way to control how many asssist to resolve during the assist resolution. | ||
101 | /// When an assist is resolved, its edits are calculated that might be costly to always do by default. | ||
102 | #[derive(Debug)] | ||
103 | pub enum AssistResolveStrategy { | ||
104 | /// No assists should be resolved. | ||
105 | None, | ||
106 | /// All assists should be resolved. | ||
107 | All, | ||
108 | /// Only a certain assist should be resolved. | ||
109 | Single(SingleResolve), | ||
110 | } | ||
111 | |||
112 | /// Hold the [`AssistId`] data of a certain assist to resolve. | ||
113 | /// The original id object cannot be used due to a `'static` lifetime | ||
114 | /// and the requirement to construct this struct dynamically during the resolve handling. | ||
115 | #[derive(Debug)] | ||
116 | pub struct SingleResolve { | ||
117 | /// The id of the assist. | ||
118 | pub assist_id: String, | ||
119 | // The kind of the assist. | ||
120 | pub assist_kind: AssistKind, | ||
121 | } | ||
122 | |||
123 | impl AssistResolveStrategy { | ||
124 | pub fn should_resolve(&self, id: &AssistId) -> bool { | ||
125 | match self { | ||
126 | AssistResolveStrategy::None => false, | ||
127 | AssistResolveStrategy::All => true, | ||
128 | AssistResolveStrategy::Single(single_resolve) => { | ||
129 | single_resolve.assist_id == id.0 && single_resolve.assist_kind == id.1 | ||
130 | } | ||
131 | } | ||
132 | } | ||
133 | } | ||
134 | |||
135 | #[derive(Clone, Debug)] | ||
136 | pub struct GroupLabel(pub String); | ||
diff --git a/crates/ide_db/src/helpers/insert_use/tests.rs b/crates/ide_db/src/helpers/insert_use/tests.rs index 70b11bf81..5a88ec742 100644 --- a/crates/ide_db/src/helpers/insert_use/tests.rs +++ b/crates/ide_db/src/helpers/insert_use/tests.rs | |||
@@ -511,13 +511,14 @@ use std::io; | |||
511 | } | 511 | } |
512 | 512 | ||
513 | #[test] | 513 | #[test] |
514 | #[ignore] // FIXME: Support this | ||
515 | fn split_out_merge() { | 514 | fn split_out_merge() { |
515 | // FIXME: This is suboptimal, we want to get `use std::fmt::{self, Result}` | ||
516 | // instead. | ||
516 | check_module( | 517 | check_module( |
517 | "std::fmt::Result", | 518 | "std::fmt::Result", |
518 | r"use std::{fmt, io};", | 519 | r"use std::{fmt, io};", |
519 | r"use std::fmt::{self, Result}; | 520 | r"use std::fmt::Result; |
520 | use std::io;", | 521 | use std::{fmt, io};", |
521 | ) | 522 | ) |
522 | } | 523 | } |
523 | 524 | ||
diff --git a/crates/ide_db/src/lib.rs b/crates/ide_db/src/lib.rs index 105607dca..7bbd08d6f 100644 --- a/crates/ide_db/src/lib.rs +++ b/crates/ide_db/src/lib.rs | |||
@@ -3,11 +3,11 @@ | |||
3 | //! It is mainly a `HirDatabase` for semantic analysis, plus a `SymbolsDatabase`, for fuzzy search. | 3 | //! It is mainly a `HirDatabase` for semantic analysis, plus a `SymbolsDatabase`, for fuzzy search. |
4 | 4 | ||
5 | mod apply_change; | 5 | mod apply_change; |
6 | pub mod assists; | ||
6 | pub mod label; | 7 | pub mod label; |
7 | pub mod line_index; | 8 | pub mod line_index; |
8 | pub mod symbol_index; | 9 | pub mod symbol_index; |
9 | pub mod defs; | 10 | pub mod defs; |
10 | pub mod search; | ||
11 | pub mod items_locator; | 11 | pub mod items_locator; |
12 | pub mod source_change; | 12 | pub mod source_change; |
13 | pub mod ty_filter; | 13 | pub mod ty_filter; |
@@ -15,6 +15,9 @@ pub mod traits; | |||
15 | pub mod call_info; | 15 | pub mod call_info; |
16 | pub mod helpers; | 16 | pub mod helpers; |
17 | 17 | ||
18 | pub mod search; | ||
19 | pub mod rename; | ||
20 | |||
18 | use std::{fmt, sync::Arc}; | 21 | use std::{fmt, sync::Arc}; |
19 | 22 | ||
20 | use base_db::{ | 23 | use base_db::{ |
diff --git a/crates/ide_db/src/rename.rs b/crates/ide_db/src/rename.rs new file mode 100644 index 000000000..643e67781 --- /dev/null +++ b/crates/ide_db/src/rename.rs | |||
@@ -0,0 +1,468 @@ | |||
1 | //! Rename infrastructure for rust-analyzer. It is used primarily for the | ||
2 | //! literal "rename" in the ide (look for tests there), but it is also available | ||
3 | //! as a general-purpose service. For example, it is used by the fix for the | ||
4 | //! "incorrect case" diagnostic. | ||
5 | //! | ||
6 | //! It leverages the [`crate::search`] functionality to find what needs to be | ||
7 | //! renamed. The actual renames are tricky -- field shorthands need special | ||
8 | //! attention, and, when renaming modules, you also want to rename files on the | ||
9 | //! file system. | ||
10 | //! | ||
11 | //! Another can of worms are macros: | ||
12 | //! | ||
13 | //! ``` | ||
14 | //! macro_rules! m { () => { fn f() {} } } | ||
15 | //! m!(); | ||
16 | //! fn main() { | ||
17 | //! f() // <- rename me | ||
18 | //! } | ||
19 | //! ``` | ||
20 | //! | ||
21 | //! The correct behavior in such cases is probably to show a dialog to the user. | ||
22 | //! Our current behavior is ¯\_(ツ)_/¯. | ||
23 | use std::fmt; | ||
24 | |||
25 | use base_db::{AnchoredPathBuf, FileId, FileRange}; | ||
26 | use either::Either; | ||
27 | use hir::{AsAssocItem, FieldSource, HasSource, InFile, ModuleSource, Semantics}; | ||
28 | use stdx::never; | ||
29 | use syntax::{ | ||
30 | ast::{self, NameOwner}, | ||
31 | lex_single_syntax_kind, AstNode, SyntaxKind, TextRange, T, | ||
32 | }; | ||
33 | use text_edit::TextEdit; | ||
34 | |||
35 | use crate::{ | ||
36 | defs::Definition, | ||
37 | search::FileReference, | ||
38 | source_change::{FileSystemEdit, SourceChange}, | ||
39 | RootDatabase, | ||
40 | }; | ||
41 | |||
42 | pub type Result<T, E = RenameError> = std::result::Result<T, E>; | ||
43 | |||
44 | #[derive(Debug)] | ||
45 | pub struct RenameError(pub String); | ||
46 | |||
47 | impl fmt::Display for RenameError { | ||
48 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||
49 | fmt::Display::fmt(&self.0, f) | ||
50 | } | ||
51 | } | ||
52 | |||
53 | #[macro_export] | ||
54 | macro_rules! _format_err { | ||
55 | ($fmt:expr) => { RenameError(format!($fmt)) }; | ||
56 | ($fmt:expr, $($arg:tt)+) => { RenameError(format!($fmt, $($arg)+)) } | ||
57 | } | ||
58 | pub use _format_err as format_err; | ||
59 | |||
60 | #[macro_export] | ||
61 | macro_rules! _bail { | ||
62 | ($($tokens:tt)*) => { return Err(format_err!($($tokens)*)) } | ||
63 | } | ||
64 | pub use _bail as bail; | ||
65 | |||
66 | impl Definition { | ||
67 | pub fn rename(&self, sema: &Semantics<RootDatabase>, new_name: &str) -> Result<SourceChange> { | ||
68 | match *self { | ||
69 | Definition::ModuleDef(hir::ModuleDef::Module(module)) => { | ||
70 | rename_mod(sema, module, new_name) | ||
71 | } | ||
72 | Definition::ModuleDef(hir::ModuleDef::BuiltinType(_)) => { | ||
73 | bail!("Cannot rename builtin type") | ||
74 | } | ||
75 | Definition::SelfType(_) => bail!("Cannot rename `Self`"), | ||
76 | def => rename_reference(sema, def, new_name), | ||
77 | } | ||
78 | } | ||
79 | |||
80 | /// Textual range of the identifier which will change when renaming this | ||
81 | /// `Definition`. Note that some definitions, like buitin types, can't be | ||
82 | /// renamed. | ||
83 | pub fn range_for_rename(self, sema: &Semantics<RootDatabase>) -> Option<FileRange> { | ||
84 | // FIXME: the `original_file_range` calls here are wrong -- they never fail, | ||
85 | // and _fall back_ to the entirety of the macro call. Such fall back is | ||
86 | // incorrect for renames. The safe behavior would be to return an error for | ||
87 | // such cases. The correct behavior would be to return an auxiliary list of | ||
88 | // "can't rename these occurrences in macros" items, and then show some kind | ||
89 | // of a dialog to the user. See: | ||
90 | cov_mark::hit!(macros_are_broken_lol); | ||
91 | |||
92 | let res = match self { | ||
93 | Definition::Macro(mac) => { | ||
94 | let src = mac.source(sema.db)?; | ||
95 | let name = match &src.value { | ||
96 | Either::Left(it) => it.name()?, | ||
97 | Either::Right(it) => it.name()?, | ||
98 | }; | ||
99 | src.with_value(name.syntax()).original_file_range(sema.db) | ||
100 | } | ||
101 | Definition::Field(field) => { | ||
102 | let src = field.source(sema.db)?; | ||
103 | |||
104 | match &src.value { | ||
105 | FieldSource::Named(record_field) => { | ||
106 | let name = record_field.name()?; | ||
107 | src.with_value(name.syntax()).original_file_range(sema.db) | ||
108 | } | ||
109 | FieldSource::Pos(_) => { | ||
110 | return None; | ||
111 | } | ||
112 | } | ||
113 | } | ||
114 | Definition::ModuleDef(module_def) => match module_def { | ||
115 | hir::ModuleDef::Module(module) => { | ||
116 | let src = module.declaration_source(sema.db)?; | ||
117 | let name = src.value.name()?; | ||
118 | src.with_value(name.syntax()).original_file_range(sema.db) | ||
119 | } | ||
120 | hir::ModuleDef::Function(it) => name_range(it, sema)?, | ||
121 | hir::ModuleDef::Adt(adt) => match adt { | ||
122 | hir::Adt::Struct(it) => name_range(it, sema)?, | ||
123 | hir::Adt::Union(it) => name_range(it, sema)?, | ||
124 | hir::Adt::Enum(it) => name_range(it, sema)?, | ||
125 | }, | ||
126 | hir::ModuleDef::Variant(it) => name_range(it, sema)?, | ||
127 | hir::ModuleDef::Const(it) => name_range(it, sema)?, | ||
128 | hir::ModuleDef::Static(it) => name_range(it, sema)?, | ||
129 | hir::ModuleDef::Trait(it) => name_range(it, sema)?, | ||
130 | hir::ModuleDef::TypeAlias(it) => name_range(it, sema)?, | ||
131 | hir::ModuleDef::BuiltinType(_) => return None, | ||
132 | }, | ||
133 | Definition::SelfType(_) => return None, | ||
134 | Definition::Local(local) => { | ||
135 | let src = local.source(sema.db); | ||
136 | let name = match &src.value { | ||
137 | Either::Left(bind_pat) => bind_pat.name()?, | ||
138 | Either::Right(_) => return None, | ||
139 | }; | ||
140 | src.with_value(name.syntax()).original_file_range(sema.db) | ||
141 | } | ||
142 | Definition::GenericParam(generic_param) => match generic_param { | ||
143 | hir::GenericParam::TypeParam(type_param) => { | ||
144 | let src = type_param.source(sema.db)?; | ||
145 | let name = match &src.value { | ||
146 | Either::Left(type_param) => type_param.name()?, | ||
147 | Either::Right(_trait) => return None, | ||
148 | }; | ||
149 | src.with_value(name.syntax()).original_file_range(sema.db) | ||
150 | } | ||
151 | hir::GenericParam::LifetimeParam(lifetime_param) => { | ||
152 | let src = lifetime_param.source(sema.db)?; | ||
153 | let lifetime = src.value.lifetime()?; | ||
154 | src.with_value(lifetime.syntax()).original_file_range(sema.db) | ||
155 | } | ||
156 | hir::GenericParam::ConstParam(it) => name_range(it, sema)?, | ||
157 | }, | ||
158 | Definition::Label(label) => { | ||
159 | let src = label.source(sema.db); | ||
160 | let lifetime = src.value.lifetime()?; | ||
161 | src.with_value(lifetime.syntax()).original_file_range(sema.db) | ||
162 | } | ||
163 | }; | ||
164 | return Some(res); | ||
165 | |||
166 | fn name_range<D>(def: D, sema: &Semantics<RootDatabase>) -> Option<FileRange> | ||
167 | where | ||
168 | D: HasSource, | ||
169 | D::Ast: ast::NameOwner, | ||
170 | { | ||
171 | let src = def.source(sema.db)?; | ||
172 | let name = src.value.name()?; | ||
173 | let res = src.with_value(name.syntax()).original_file_range(sema.db); | ||
174 | Some(res) | ||
175 | } | ||
176 | } | ||
177 | } | ||
178 | |||
179 | fn rename_mod( | ||
180 | sema: &Semantics<RootDatabase>, | ||
181 | module: hir::Module, | ||
182 | new_name: &str, | ||
183 | ) -> Result<SourceChange> { | ||
184 | if IdentifierKind::classify(new_name)? != IdentifierKind::Ident { | ||
185 | bail!("Invalid name `{0}`: cannot rename module to {0}", new_name); | ||
186 | } | ||
187 | |||
188 | let mut source_change = SourceChange::default(); | ||
189 | |||
190 | let InFile { file_id, value: def_source } = module.definition_source(sema.db); | ||
191 | let file_id = file_id.original_file(sema.db); | ||
192 | if let ModuleSource::SourceFile(..) = def_source { | ||
193 | // mod is defined in path/to/dir/mod.rs | ||
194 | let path = if module.is_mod_rs(sema.db) { | ||
195 | format!("../{}/mod.rs", new_name) | ||
196 | } else { | ||
197 | format!("{}.rs", new_name) | ||
198 | }; | ||
199 | let dst = AnchoredPathBuf { anchor: file_id, path }; | ||
200 | let move_file = FileSystemEdit::MoveFile { src: file_id, dst }; | ||
201 | source_change.push_file_system_edit(move_file); | ||
202 | } | ||
203 | |||
204 | if let Some(InFile { file_id, value: decl_source }) = module.declaration_source(sema.db) { | ||
205 | let file_id = file_id.original_file(sema.db); | ||
206 | match decl_source.name() { | ||
207 | Some(name) => source_change.insert_source_edit( | ||
208 | file_id, | ||
209 | TextEdit::replace(name.syntax().text_range(), new_name.to_string()), | ||
210 | ), | ||
211 | _ => never!("Module source node is missing a name"), | ||
212 | } | ||
213 | } | ||
214 | let def = Definition::ModuleDef(hir::ModuleDef::Module(module)); | ||
215 | let usages = def.usages(sema).all(); | ||
216 | let ref_edits = usages.iter().map(|(&file_id, references)| { | ||
217 | (file_id, source_edit_from_references(references, def, new_name)) | ||
218 | }); | ||
219 | source_change.extend(ref_edits); | ||
220 | |||
221 | Ok(source_change) | ||
222 | } | ||
223 | |||
224 | fn rename_reference( | ||
225 | sema: &Semantics<RootDatabase>, | ||
226 | mut def: Definition, | ||
227 | new_name: &str, | ||
228 | ) -> Result<SourceChange> { | ||
229 | let ident_kind = IdentifierKind::classify(new_name)?; | ||
230 | |||
231 | if matches!( | ||
232 | def, // is target a lifetime? | ||
233 | Definition::GenericParam(hir::GenericParam::LifetimeParam(_)) | Definition::Label(_) | ||
234 | ) { | ||
235 | match ident_kind { | ||
236 | IdentifierKind::Ident | IdentifierKind::Underscore => { | ||
237 | cov_mark::hit!(rename_not_a_lifetime_ident_ref); | ||
238 | bail!("Invalid name `{}`: not a lifetime identifier", new_name); | ||
239 | } | ||
240 | IdentifierKind::Lifetime => cov_mark::hit!(rename_lifetime), | ||
241 | } | ||
242 | } else { | ||
243 | match (ident_kind, def) { | ||
244 | (IdentifierKind::Lifetime, _) => { | ||
245 | cov_mark::hit!(rename_not_an_ident_ref); | ||
246 | bail!("Invalid name `{}`: not an identifier", new_name); | ||
247 | } | ||
248 | (IdentifierKind::Ident, _) => cov_mark::hit!(rename_non_local), | ||
249 | (IdentifierKind::Underscore, _) => (), | ||
250 | } | ||
251 | } | ||
252 | |||
253 | def = match def { | ||
254 | // HACK: resolve trait impl items to the item def of the trait definition | ||
255 | // so that we properly resolve all trait item references | ||
256 | Definition::ModuleDef(mod_def) => mod_def | ||
257 | .as_assoc_item(sema.db) | ||
258 | .and_then(|it| it.containing_trait_impl(sema.db)) | ||
259 | .and_then(|it| { | ||
260 | it.items(sema.db).into_iter().find_map(|it| match (it, mod_def) { | ||
261 | (hir::AssocItem::Function(trait_func), hir::ModuleDef::Function(func)) | ||
262 | if trait_func.name(sema.db) == func.name(sema.db) => | ||
263 | { | ||
264 | Some(Definition::ModuleDef(hir::ModuleDef::Function(trait_func))) | ||
265 | } | ||
266 | (hir::AssocItem::Const(trait_konst), hir::ModuleDef::Const(konst)) | ||
267 | if trait_konst.name(sema.db) == konst.name(sema.db) => | ||
268 | { | ||
269 | Some(Definition::ModuleDef(hir::ModuleDef::Const(trait_konst))) | ||
270 | } | ||
271 | ( | ||
272 | hir::AssocItem::TypeAlias(trait_type_alias), | ||
273 | hir::ModuleDef::TypeAlias(type_alias), | ||
274 | ) if trait_type_alias.name(sema.db) == type_alias.name(sema.db) => { | ||
275 | Some(Definition::ModuleDef(hir::ModuleDef::TypeAlias(trait_type_alias))) | ||
276 | } | ||
277 | _ => None, | ||
278 | }) | ||
279 | }) | ||
280 | .unwrap_or(def), | ||
281 | _ => def, | ||
282 | }; | ||
283 | let usages = def.usages(sema).all(); | ||
284 | |||
285 | if !usages.is_empty() && ident_kind == IdentifierKind::Underscore { | ||
286 | cov_mark::hit!(rename_underscore_multiple); | ||
287 | bail!("Cannot rename reference to `_` as it is being referenced multiple times"); | ||
288 | } | ||
289 | let mut source_change = SourceChange::default(); | ||
290 | source_change.extend(usages.iter().map(|(&file_id, references)| { | ||
291 | (file_id, source_edit_from_references(references, def, new_name)) | ||
292 | })); | ||
293 | |||
294 | let (file_id, edit) = source_edit_from_def(sema, def, new_name)?; | ||
295 | source_change.insert_source_edit(file_id, edit); | ||
296 | Ok(source_change) | ||
297 | } | ||
298 | |||
299 | pub fn source_edit_from_references( | ||
300 | references: &[FileReference], | ||
301 | def: Definition, | ||
302 | new_name: &str, | ||
303 | ) -> TextEdit { | ||
304 | let mut edit = TextEdit::builder(); | ||
305 | for reference in references { | ||
306 | let (range, replacement) = match &reference.name { | ||
307 | // if the ranges differ then the node is inside a macro call, we can't really attempt | ||
308 | // to make special rewrites like shorthand syntax and such, so just rename the node in | ||
309 | // the macro input | ||
310 | ast::NameLike::NameRef(name_ref) | ||
311 | if name_ref.syntax().text_range() == reference.range => | ||
312 | { | ||
313 | source_edit_from_name_ref(name_ref, new_name, def) | ||
314 | } | ||
315 | ast::NameLike::Name(name) if name.syntax().text_range() == reference.range => { | ||
316 | source_edit_from_name(name, new_name) | ||
317 | } | ||
318 | _ => None, | ||
319 | } | ||
320 | .unwrap_or_else(|| (reference.range, new_name.to_string())); | ||
321 | edit.replace(range, replacement); | ||
322 | } | ||
323 | edit.finish() | ||
324 | } | ||
325 | |||
326 | fn source_edit_from_name(name: &ast::Name, new_name: &str) -> Option<(TextRange, String)> { | ||
327 | if let Some(_) = ast::RecordPatField::for_field_name(name) { | ||
328 | if let Some(ident_pat) = name.syntax().parent().and_then(ast::IdentPat::cast) { | ||
329 | return Some(( | ||
330 | TextRange::empty(ident_pat.syntax().text_range().start()), | ||
331 | [new_name, ": "].concat(), | ||
332 | )); | ||
333 | } | ||
334 | } | ||
335 | None | ||
336 | } | ||
337 | |||
338 | fn source_edit_from_name_ref( | ||
339 | name_ref: &ast::NameRef, | ||
340 | new_name: &str, | ||
341 | def: Definition, | ||
342 | ) -> Option<(TextRange, String)> { | ||
343 | if let Some(record_field) = ast::RecordExprField::for_name_ref(name_ref) { | ||
344 | let rcf_name_ref = record_field.name_ref(); | ||
345 | let rcf_expr = record_field.expr(); | ||
346 | match (rcf_name_ref, rcf_expr.and_then(|it| it.name_ref())) { | ||
347 | // field: init-expr, check if we can use a field init shorthand | ||
348 | (Some(field_name), Some(init)) => { | ||
349 | if field_name == *name_ref { | ||
350 | if init.text() == new_name { | ||
351 | cov_mark::hit!(test_rename_field_put_init_shorthand); | ||
352 | // same names, we can use a shorthand here instead. | ||
353 | // we do not want to erase attributes hence this range start | ||
354 | let s = field_name.syntax().text_range().start(); | ||
355 | let e = record_field.syntax().text_range().end(); | ||
356 | return Some((TextRange::new(s, e), new_name.to_owned())); | ||
357 | } | ||
358 | } else if init == *name_ref { | ||
359 | if field_name.text() == new_name { | ||
360 | cov_mark::hit!(test_rename_local_put_init_shorthand); | ||
361 | // same names, we can use a shorthand here instead. | ||
362 | // we do not want to erase attributes hence this range start | ||
363 | let s = field_name.syntax().text_range().start(); | ||
364 | let e = record_field.syntax().text_range().end(); | ||
365 | return Some((TextRange::new(s, e), new_name.to_owned())); | ||
366 | } | ||
367 | } | ||
368 | None | ||
369 | } | ||
370 | // init shorthand | ||
371 | // FIXME: instead of splitting the shorthand, recursively trigger a rename of the | ||
372 | // other name https://github.com/rust-analyzer/rust-analyzer/issues/6547 | ||
373 | (None, Some(_)) if matches!(def, Definition::Field(_)) => { | ||
374 | cov_mark::hit!(test_rename_field_in_field_shorthand); | ||
375 | let s = name_ref.syntax().text_range().start(); | ||
376 | Some((TextRange::empty(s), format!("{}: ", new_name))) | ||
377 | } | ||
378 | (None, Some(_)) if matches!(def, Definition::Local(_)) => { | ||
379 | cov_mark::hit!(test_rename_local_in_field_shorthand); | ||
380 | let s = name_ref.syntax().text_range().end(); | ||
381 | Some((TextRange::empty(s), format!(": {}", new_name))) | ||
382 | } | ||
383 | _ => None, | ||
384 | } | ||
385 | } else if let Some(record_field) = ast::RecordPatField::for_field_name_ref(name_ref) { | ||
386 | let rcf_name_ref = record_field.name_ref(); | ||
387 | let rcf_pat = record_field.pat(); | ||
388 | match (rcf_name_ref, rcf_pat) { | ||
389 | // field: rename | ||
390 | (Some(field_name), Some(ast::Pat::IdentPat(pat))) if field_name == *name_ref => { | ||
391 | // field name is being renamed | ||
392 | if pat.name().map_or(false, |it| it.text() == new_name) { | ||
393 | cov_mark::hit!(test_rename_field_put_init_shorthand_pat); | ||
394 | // same names, we can use a shorthand here instead/ | ||
395 | // we do not want to erase attributes hence this range start | ||
396 | let s = field_name.syntax().text_range().start(); | ||
397 | let e = record_field.syntax().text_range().end(); | ||
398 | Some((TextRange::new(s, e), pat.to_string())) | ||
399 | } else { | ||
400 | None | ||
401 | } | ||
402 | } | ||
403 | _ => None, | ||
404 | } | ||
405 | } else { | ||
406 | None | ||
407 | } | ||
408 | } | ||
409 | |||
410 | fn source_edit_from_def( | ||
411 | sema: &Semantics<RootDatabase>, | ||
412 | def: Definition, | ||
413 | new_name: &str, | ||
414 | ) -> Result<(FileId, TextEdit)> { | ||
415 | let frange = def | ||
416 | .range_for_rename(sema) | ||
417 | .ok_or_else(|| format_err!("No identifier available to rename"))?; | ||
418 | |||
419 | let mut replacement_text = String::new(); | ||
420 | let mut repl_range = frange.range; | ||
421 | if let Definition::Local(local) = def { | ||
422 | if let Either::Left(pat) = local.source(sema.db).value { | ||
423 | if matches!( | ||
424 | pat.syntax().parent().and_then(ast::RecordPatField::cast), | ||
425 | Some(pat_field) if pat_field.name_ref().is_none() | ||
426 | ) { | ||
427 | replacement_text.push_str(": "); | ||
428 | replacement_text.push_str(new_name); | ||
429 | repl_range = TextRange::new( | ||
430 | pat.syntax().text_range().end(), | ||
431 | pat.syntax().text_range().end(), | ||
432 | ); | ||
433 | } | ||
434 | } | ||
435 | } | ||
436 | if replacement_text.is_empty() { | ||
437 | replacement_text.push_str(new_name); | ||
438 | } | ||
439 | let edit = TextEdit::replace(repl_range, replacement_text); | ||
440 | Ok((frange.file_id, edit)) | ||
441 | } | ||
442 | |||
443 | #[derive(Copy, Clone, Debug, PartialEq)] | ||
444 | pub enum IdentifierKind { | ||
445 | Ident, | ||
446 | Lifetime, | ||
447 | Underscore, | ||
448 | } | ||
449 | |||
450 | impl IdentifierKind { | ||
451 | pub fn classify(new_name: &str) -> Result<IdentifierKind> { | ||
452 | match lex_single_syntax_kind(new_name) { | ||
453 | Some(res) => match res { | ||
454 | (SyntaxKind::IDENT, _) => Ok(IdentifierKind::Ident), | ||
455 | (T![_], _) => Ok(IdentifierKind::Underscore), | ||
456 | (SyntaxKind::LIFETIME_IDENT, _) if new_name != "'static" && new_name != "'_" => { | ||
457 | Ok(IdentifierKind::Lifetime) | ||
458 | } | ||
459 | (SyntaxKind::LIFETIME_IDENT, _) => { | ||
460 | bail!("Invalid name `{}`: not a lifetime identifier", new_name) | ||
461 | } | ||
462 | (_, Some(syntax_error)) => bail!("Invalid name `{}`: {}", new_name, syntax_error), | ||
463 | (_, None) => bail!("Invalid name `{}`: not an identifier", new_name), | ||
464 | }, | ||
465 | None => bail!("Invalid name `{}`: not an identifier", new_name), | ||
466 | } | ||
467 | } | ||
468 | } | ||
diff --git a/crates/ide_diagnostics/Cargo.toml b/crates/ide_diagnostics/Cargo.toml new file mode 100644 index 000000000..fa2adf212 --- /dev/null +++ b/crates/ide_diagnostics/Cargo.toml | |||
@@ -0,0 +1,29 @@ | |||
1 | [package] | ||
2 | name = "ide_diagnostics" | ||
3 | version = "0.0.0" | ||
4 | description = "TBD" | ||
5 | license = "MIT OR Apache-2.0" | ||
6 | authors = ["rust-analyzer developers"] | ||
7 | edition = "2018" | ||
8 | |||
9 | [lib] | ||
10 | doctest = false | ||
11 | |||
12 | [dependencies] | ||
13 | cov-mark = "2.0.0-pre.1" | ||
14 | itertools = "0.10.0" | ||
15 | rustc-hash = "1.1.0" | ||
16 | either = "1.5.3" | ||
17 | |||
18 | profile = { path = "../profile", version = "0.0.0" } | ||
19 | stdx = { path = "../stdx", version = "0.0.0" } | ||
20 | syntax = { path = "../syntax", version = "0.0.0" } | ||
21 | text_edit = { path = "../text_edit", version = "0.0.0" } | ||
22 | cfg = { path = "../cfg", version = "0.0.0" } | ||
23 | hir = { path = "../hir", version = "0.0.0" } | ||
24 | ide_db = { path = "../ide_db", version = "0.0.0" } | ||
25 | |||
26 | [dev-dependencies] | ||
27 | expect-test = "1.1" | ||
28 | |||
29 | test_utils = { path = "../test_utils" } | ||
diff --git a/crates/ide/src/diagnostics/break_outside_of_loop.rs b/crates/ide_diagnostics/src/handlers/break_outside_of_loop.rs index 80e68f3cc..d12594a4c 100644 --- a/crates/ide/src/diagnostics/break_outside_of_loop.rs +++ b/crates/ide_diagnostics/src/handlers/break_outside_of_loop.rs | |||
@@ -1,9 +1,9 @@ | |||
1 | use crate::diagnostics::{Diagnostic, DiagnosticsContext}; | 1 | use crate::{Diagnostic, DiagnosticsContext}; |
2 | 2 | ||
3 | // Diagnostic: break-outside-of-loop | 3 | // Diagnostic: break-outside-of-loop |
4 | // | 4 | // |
5 | // This diagnostic is triggered if the `break` keyword is used outside of a loop. | 5 | // This diagnostic is triggered if the `break` keyword is used outside of a loop. |
6 | pub(super) fn break_outside_of_loop( | 6 | pub(crate) fn break_outside_of_loop( |
7 | ctx: &DiagnosticsContext<'_>, | 7 | ctx: &DiagnosticsContext<'_>, |
8 | d: &hir::BreakOutsideOfLoop, | 8 | d: &hir::BreakOutsideOfLoop, |
9 | ) -> Diagnostic { | 9 | ) -> Diagnostic { |
@@ -16,14 +16,14 @@ pub(super) fn break_outside_of_loop( | |||
16 | 16 | ||
17 | #[cfg(test)] | 17 | #[cfg(test)] |
18 | mod tests { | 18 | mod tests { |
19 | use crate::diagnostics::tests::check_diagnostics; | 19 | use crate::tests::check_diagnostics; |
20 | 20 | ||
21 | #[test] | 21 | #[test] |
22 | fn break_outside_of_loop() { | 22 | fn break_outside_of_loop() { |
23 | check_diagnostics( | 23 | check_diagnostics( |
24 | r#" | 24 | r#" |
25 | fn foo() { break; } | 25 | fn foo() { break; } |
26 | //^^^^^ break outside of loop | 26 | //^^^^^ error: break outside of loop |
27 | "#, | 27 | "#, |
28 | ); | 28 | ); |
29 | } | 29 | } |
diff --git a/crates/ide/src/diagnostics/field_shorthand.rs b/crates/ide_diagnostics/src/handlers/field_shorthand.rs index c7f4dab8e..33152e284 100644 --- a/crates/ide/src/diagnostics/field_shorthand.rs +++ b/crates/ide_diagnostics/src/handlers/field_shorthand.rs | |||
@@ -5,9 +5,9 @@ use ide_db::{base_db::FileId, source_change::SourceChange}; | |||
5 | use syntax::{ast, match_ast, AstNode, SyntaxNode}; | 5 | use syntax::{ast, match_ast, AstNode, SyntaxNode}; |
6 | use text_edit::TextEdit; | 6 | use text_edit::TextEdit; |
7 | 7 | ||
8 | use crate::{diagnostics::fix, Diagnostic, Severity}; | 8 | use crate::{fix, Diagnostic, Severity}; |
9 | 9 | ||
10 | pub(super) fn check(acc: &mut Vec<Diagnostic>, file_id: FileId, node: &SyntaxNode) { | 10 | pub(crate) fn field_shorthand(acc: &mut Vec<Diagnostic>, file_id: FileId, node: &SyntaxNode) { |
11 | match_ast! { | 11 | match_ast! { |
12 | match node { | 12 | match node { |
13 | ast::RecordExpr(it) => check_expr_field_shorthand(acc, file_id, it), | 13 | ast::RecordExpr(it) => check_expr_field_shorthand(acc, file_id, it), |
@@ -101,7 +101,7 @@ fn check_pat_field_shorthand( | |||
101 | 101 | ||
102 | #[cfg(test)] | 102 | #[cfg(test)] |
103 | mod tests { | 103 | mod tests { |
104 | use crate::diagnostics::tests::{check_diagnostics, check_fix}; | 104 | use crate::tests::{check_diagnostics, check_fix}; |
105 | 105 | ||
106 | #[test] | 106 | #[test] |
107 | fn test_check_expr_field_shorthand() { | 107 | fn test_check_expr_field_shorthand() { |
diff --git a/crates/ide/src/diagnostics/inactive_code.rs b/crates/ide_diagnostics/src/handlers/inactive_code.rs index d9d3e88c1..dfd0e3351 100644 --- a/crates/ide/src/diagnostics/inactive_code.rs +++ b/crates/ide_diagnostics/src/handlers/inactive_code.rs | |||
@@ -1,15 +1,12 @@ | |||
1 | use cfg::DnfExpr; | 1 | use cfg::DnfExpr; |
2 | use stdx::format_to; | 2 | use stdx::format_to; |
3 | 3 | ||
4 | use crate::{ | 4 | use crate::{Diagnostic, DiagnosticsContext, Severity}; |
5 | diagnostics::{Diagnostic, DiagnosticsContext}, | ||
6 | Severity, | ||
7 | }; | ||
8 | 5 | ||
9 | // Diagnostic: inactive-code | 6 | // Diagnostic: inactive-code |
10 | // | 7 | // |
11 | // This diagnostic is shown for code with inactive `#[cfg]` attributes. | 8 | // This diagnostic is shown for code with inactive `#[cfg]` attributes. |
12 | pub(super) fn inactive_code( | 9 | pub(crate) fn inactive_code( |
13 | ctx: &DiagnosticsContext<'_>, | 10 | ctx: &DiagnosticsContext<'_>, |
14 | d: &hir::InactiveCode, | 11 | d: &hir::InactiveCode, |
15 | ) -> Option<Diagnostic> { | 12 | ) -> Option<Diagnostic> { |
@@ -37,7 +34,7 @@ pub(super) fn inactive_code( | |||
37 | 34 | ||
38 | #[cfg(test)] | 35 | #[cfg(test)] |
39 | mod tests { | 36 | mod tests { |
40 | use crate::{diagnostics::tests::check_diagnostics_with_config, DiagnosticsConfig}; | 37 | use crate::{tests::check_diagnostics_with_config, DiagnosticsConfig}; |
41 | 38 | ||
42 | pub(crate) fn check(ra_fixture: &str) { | 39 | pub(crate) fn check(ra_fixture: &str) { |
43 | let config = DiagnosticsConfig::default(); | 40 | let config = DiagnosticsConfig::default(); |
@@ -52,26 +49,26 @@ fn f() { | |||
52 | // The three g̶e̶n̶d̶e̶r̶s̶ statements: | 49 | // The three g̶e̶n̶d̶e̶r̶s̶ statements: |
53 | 50 | ||
54 | #[cfg(a)] fn f() {} // Item statement | 51 | #[cfg(a)] fn f() {} // Item statement |
55 | //^^^^^^^^^^^^^^^^^^^ code is inactive due to #[cfg] directives: a is disabled | 52 | //^^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: a is disabled |
56 | #[cfg(a)] {} // Expression statement | 53 | #[cfg(a)] {} // Expression statement |
57 | //^^^^^^^^^^^^ code is inactive due to #[cfg] directives: a is disabled | 54 | //^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: a is disabled |
58 | #[cfg(a)] let x = 0; // let statement | 55 | #[cfg(a)] let x = 0; // let statement |
59 | //^^^^^^^^^^^^^^^^^^^^ code is inactive due to #[cfg] directives: a is disabled | 56 | //^^^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: a is disabled |
60 | 57 | ||
61 | abc(#[cfg(a)] 0); | 58 | abc(#[cfg(a)] 0); |
62 | //^^^^^^^^^^^ code is inactive due to #[cfg] directives: a is disabled | 59 | //^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: a is disabled |
63 | let x = Struct { | 60 | let x = Struct { |
64 | #[cfg(a)] f: 0, | 61 | #[cfg(a)] f: 0, |
65 | //^^^^^^^^^^^^^^ code is inactive due to #[cfg] directives: a is disabled | 62 | //^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: a is disabled |
66 | }; | 63 | }; |
67 | match () { | 64 | match () { |
68 | () => (), | 65 | () => (), |
69 | #[cfg(a)] () => (), | 66 | #[cfg(a)] () => (), |
70 | //^^^^^^^^^^^^^^^^^^ code is inactive due to #[cfg] directives: a is disabled | 67 | //^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: a is disabled |
71 | } | 68 | } |
72 | 69 | ||
73 | #[cfg(a)] 0 // Trailing expression of block | 70 | #[cfg(a)] 0 // Trailing expression of block |
74 | //^^^^^^^^^^^ code is inactive due to #[cfg] directives: a is disabled | 71 | //^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: a is disabled |
75 | } | 72 | } |
76 | "#, | 73 | "#, |
77 | ); | 74 | ); |
@@ -84,16 +81,16 @@ fn f() { | |||
84 | check( | 81 | check( |
85 | r#" | 82 | r#" |
86 | #[cfg(no)] pub fn f() {} | 83 | #[cfg(no)] pub fn f() {} |
87 | //^^^^^^^^^^^^^^^^^^^^^^^^ code is inactive due to #[cfg] directives: no is disabled | 84 | //^^^^^^^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: no is disabled |
88 | 85 | ||
89 | #[cfg(no)] #[cfg(no2)] mod m; | 86 | #[cfg(no)] #[cfg(no2)] mod m; |
90 | //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ code is inactive due to #[cfg] directives: no and no2 are disabled | 87 | //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: no and no2 are disabled |
91 | 88 | ||
92 | #[cfg(all(not(a), b))] enum E {} | 89 | #[cfg(all(not(a), b))] enum E {} |
93 | //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ code is inactive due to #[cfg] directives: b is disabled | 90 | //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: b is disabled |
94 | 91 | ||
95 | #[cfg(feature = "std")] use std; | 92 | #[cfg(feature = "std")] use std; |
96 | //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ code is inactive due to #[cfg] directives: feature = "std" is disabled | 93 | //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: feature = "std" is disabled |
97 | "#, | 94 | "#, |
98 | ); | 95 | ); |
99 | } | 96 | } |
@@ -105,14 +102,14 @@ fn f() { | |||
105 | check( | 102 | check( |
106 | r#" | 103 | r#" |
107 | #[cfg_attr(not(never), cfg(no))] fn f() {} | 104 | #[cfg_attr(not(never), cfg(no))] fn f() {} |
108 | //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ code is inactive due to #[cfg] directives: no is disabled | 105 | //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: no is disabled |
109 | 106 | ||
110 | #[cfg_attr(not(never), cfg(not(no)))] fn f() {} | 107 | #[cfg_attr(not(never), cfg(not(no)))] fn f() {} |
111 | 108 | ||
112 | #[cfg_attr(never, cfg(no))] fn g() {} | 109 | #[cfg_attr(never, cfg(no))] fn g() {} |
113 | 110 | ||
114 | #[cfg_attr(not(never), inline, cfg(no))] fn h() {} | 111 | #[cfg_attr(not(never), inline, cfg(no))] fn h() {} |
115 | //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ code is inactive due to #[cfg] directives: no is disabled | 112 | //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: no is disabled |
116 | "#, | 113 | "#, |
117 | ); | 114 | ); |
118 | } | 115 | } |
diff --git a/crates/ide/src/diagnostics/incorrect_case.rs b/crates/ide_diagnostics/src/handlers/incorrect_case.rs index 832394400..68f25f284 100644 --- a/crates/ide/src/diagnostics/incorrect_case.rs +++ b/crates/ide_diagnostics/src/handlers/incorrect_case.rs | |||
@@ -1,18 +1,19 @@ | |||
1 | use hir::{db::AstDatabase, InFile}; | 1 | use hir::{db::AstDatabase, InFile}; |
2 | use ide_assists::Assist; | 2 | use ide_db::{assists::Assist, defs::NameClass}; |
3 | use ide_db::base_db::FilePosition; | ||
4 | use syntax::AstNode; | 3 | use syntax::AstNode; |
5 | 4 | ||
6 | use crate::{ | 5 | use crate::{ |
7 | diagnostics::{unresolved_fix, Diagnostic, DiagnosticsContext}, | 6 | // references::rename::rename_with_semantics, |
8 | references::rename::rename_with_semantics, | 7 | unresolved_fix, |
8 | Diagnostic, | ||
9 | DiagnosticsContext, | ||
9 | Severity, | 10 | Severity, |
10 | }; | 11 | }; |
11 | 12 | ||
12 | // Diagnostic: incorrect-ident-case | 13 | // Diagnostic: incorrect-ident-case |
13 | // | 14 | // |
14 | // This diagnostic is triggered if an item name doesn't follow https://doc.rust-lang.org/1.0.0/style/style/naming/README.html[Rust naming convention]. | 15 | // This diagnostic is triggered if an item name doesn't follow https://doc.rust-lang.org/1.0.0/style/style/naming/README.html[Rust naming convention]. |
15 | pub(super) fn incorrect_case(ctx: &DiagnosticsContext<'_>, d: &hir::IncorrectCase) -> Diagnostic { | 16 | pub(crate) fn incorrect_case(ctx: &DiagnosticsContext<'_>, d: &hir::IncorrectCase) -> Diagnostic { |
16 | Diagnostic::new( | 17 | Diagnostic::new( |
17 | "incorrect-ident-case", | 18 | "incorrect-ident-case", |
18 | format!( | 19 | format!( |
@@ -28,15 +29,15 @@ pub(super) fn incorrect_case(ctx: &DiagnosticsContext<'_>, d: &hir::IncorrectCas | |||
28 | fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::IncorrectCase) -> Option<Vec<Assist>> { | 29 | fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::IncorrectCase) -> Option<Vec<Assist>> { |
29 | let root = ctx.sema.db.parse_or_expand(d.file)?; | 30 | let root = ctx.sema.db.parse_or_expand(d.file)?; |
30 | let name_node = d.ident.to_node(&root); | 31 | let name_node = d.ident.to_node(&root); |
32 | let def = NameClass::classify(&ctx.sema, &name_node)?.defined(ctx.sema.db)?; | ||
31 | 33 | ||
32 | let name_node = InFile::new(d.file, name_node.syntax()); | 34 | let name_node = InFile::new(d.file, name_node.syntax()); |
33 | let frange = name_node.original_file_range(ctx.sema.db); | 35 | let frange = name_node.original_file_range(ctx.sema.db); |
34 | let file_position = FilePosition { file_id: frange.file_id, offset: frange.range.start() }; | ||
35 | 36 | ||
36 | let label = format!("Rename to {}", d.suggested_text); | 37 | let label = format!("Rename to {}", d.suggested_text); |
37 | let mut res = unresolved_fix("change_case", &label, frange.range); | 38 | let mut res = unresolved_fix("change_case", &label, frange.range); |
38 | if ctx.resolve.should_resolve(&res.id) { | 39 | if ctx.resolve.should_resolve(&res.id) { |
39 | let source_change = rename_with_semantics(&ctx.sema, file_position, &d.suggested_text); | 40 | let source_change = def.rename(&ctx.sema, &d.suggested_text); |
40 | res.source_change = Some(source_change.ok().unwrap_or_default()); | 41 | res.source_change = Some(source_change.ok().unwrap_or_default()); |
41 | } | 42 | } |
42 | 43 | ||
@@ -45,10 +46,7 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::IncorrectCase) -> Option<Vec<Ass | |||
45 | 46 | ||
46 | #[cfg(test)] | 47 | #[cfg(test)] |
47 | mod change_case { | 48 | mod change_case { |
48 | use crate::{ | 49 | use crate::tests::{check_diagnostics, check_fix}; |
49 | diagnostics::tests::{check_diagnostics, check_fix}, | ||
50 | fixture, AssistResolveStrategy, DiagnosticsConfig, | ||
51 | }; | ||
52 | 50 | ||
53 | #[test] | 51 | #[test] |
54 | fn test_rename_incorrect_case() { | 52 | fn test_rename_incorrect_case() { |
@@ -116,7 +114,7 @@ fn some_fn() { | |||
116 | check_diagnostics( | 114 | check_diagnostics( |
117 | r#" | 115 | r#" |
118 | fn foo() { | 116 | fn foo() { |
119 | const ANOTHER_ITEM$0: &str = "some_item"; | 117 | const ANOTHER_ITEM: &str = "some_item"; |
120 | } | 118 | } |
121 | "#, | 119 | "#, |
122 | ); | 120 | ); |
@@ -148,20 +146,13 @@ impl TestStruct { | |||
148 | 146 | ||
149 | #[test] | 147 | #[test] |
150 | fn test_single_incorrect_case_diagnostic_in_function_name_issue_6970() { | 148 | fn test_single_incorrect_case_diagnostic_in_function_name_issue_6970() { |
151 | let input = r#"fn FOO$0() {}"#; | 149 | check_diagnostics( |
152 | let expected = r#"fn foo() {}"#; | 150 | r#" |
153 | 151 | fn FOO() {} | |
154 | let (analysis, file_position) = fixture::position(input); | 152 | // ^^^ 💡 weak: Function `FOO` should have snake_case name, e.g. `foo` |
155 | let diagnostics = analysis | 153 | "#, |
156 | .diagnostics( | 154 | ); |
157 | &DiagnosticsConfig::default(), | 155 | check_fix(r#"fn FOO$0() {}"#, r#"fn foo() {}"#); |
158 | AssistResolveStrategy::All, | ||
159 | file_position.file_id, | ||
160 | ) | ||
161 | .unwrap(); | ||
162 | assert_eq!(diagnostics.len(), 1); | ||
163 | |||
164 | check_fix(input, expected); | ||
165 | } | 156 | } |
166 | 157 | ||
167 | #[test] | 158 | #[test] |
@@ -169,7 +160,7 @@ impl TestStruct { | |||
169 | check_diagnostics( | 160 | check_diagnostics( |
170 | r#" | 161 | r#" |
171 | fn NonSnakeCaseName() {} | 162 | fn NonSnakeCaseName() {} |
172 | // ^^^^^^^^^^^^^^^^ Function `NonSnakeCaseName` should have snake_case name, e.g. `non_snake_case_name` | 163 | // ^^^^^^^^^^^^^^^^ 💡 weak: Function `NonSnakeCaseName` should have snake_case name, e.g. `non_snake_case_name` |
173 | "#, | 164 | "#, |
174 | ); | 165 | ); |
175 | } | 166 | } |
@@ -179,10 +170,10 @@ fn NonSnakeCaseName() {} | |||
179 | check_diagnostics( | 170 | check_diagnostics( |
180 | r#" | 171 | r#" |
181 | fn foo(SomeParam: u8) {} | 172 | fn foo(SomeParam: u8) {} |
182 | // ^^^^^^^^^ Parameter `SomeParam` should have snake_case name, e.g. `some_param` | 173 | // ^^^^^^^^^ 💡 weak: Parameter `SomeParam` should have snake_case name, e.g. `some_param` |
183 | 174 | ||
184 | fn foo2(ok_param: &str, CAPS_PARAM: u8) {} | 175 | fn foo2(ok_param: &str, CAPS_PARAM: u8) {} |
185 | // ^^^^^^^^^^ Parameter `CAPS_PARAM` should have snake_case name, e.g. `caps_param` | 176 | // ^^^^^^^^^^ 💡 weak: Parameter `CAPS_PARAM` should have snake_case name, e.g. `caps_param` |
186 | "#, | 177 | "#, |
187 | ); | 178 | ); |
188 | } | 179 | } |
@@ -193,9 +184,9 @@ fn foo2(ok_param: &str, CAPS_PARAM: u8) {} | |||
193 | r#" | 184 | r#" |
194 | fn foo() { | 185 | fn foo() { |
195 | let SOME_VALUE = 10; | 186 | let SOME_VALUE = 10; |
196 | // ^^^^^^^^^^ Variable `SOME_VALUE` should have snake_case name, e.g. `some_value` | 187 | // ^^^^^^^^^^ 💡 weak: Variable `SOME_VALUE` should have snake_case name, e.g. `some_value` |
197 | let AnotherValue = 20; | 188 | let AnotherValue = 20; |
198 | // ^^^^^^^^^^^^ Variable `AnotherValue` should have snake_case name, e.g. `another_value` | 189 | // ^^^^^^^^^^^^ 💡 weak: Variable `AnotherValue` should have snake_case name, e.g. `another_value` |
199 | } | 190 | } |
200 | "#, | 191 | "#, |
201 | ); | 192 | ); |
@@ -206,10 +197,10 @@ fn foo() { | |||
206 | check_diagnostics( | 197 | check_diagnostics( |
207 | r#" | 198 | r#" |
208 | struct non_camel_case_name {} | 199 | struct non_camel_case_name {} |
209 | // ^^^^^^^^^^^^^^^^^^^ Structure `non_camel_case_name` should have CamelCase name, e.g. `NonCamelCaseName` | 200 | // ^^^^^^^^^^^^^^^^^^^ 💡 weak: Structure `non_camel_case_name` should have CamelCase name, e.g. `NonCamelCaseName` |
210 | 201 | ||
211 | struct SCREAMING_CASE {} | 202 | struct SCREAMING_CASE {} |
212 | // ^^^^^^^^^^^^^^ Structure `SCREAMING_CASE` should have CamelCase name, e.g. `ScreamingCase` | 203 | // ^^^^^^^^^^^^^^ 💡 weak: Structure `SCREAMING_CASE` should have CamelCase name, e.g. `ScreamingCase` |
213 | "#, | 204 | "#, |
214 | ); | 205 | ); |
215 | } | 206 | } |
@@ -228,7 +219,7 @@ struct AABB {} | |||
228 | check_diagnostics( | 219 | check_diagnostics( |
229 | r#" | 220 | r#" |
230 | struct SomeStruct { SomeField: u8 } | 221 | struct SomeStruct { SomeField: u8 } |
231 | // ^^^^^^^^^ Field `SomeField` should have snake_case name, e.g. `some_field` | 222 | // ^^^^^^^^^ 💡 weak: Field `SomeField` should have snake_case name, e.g. `some_field` |
232 | "#, | 223 | "#, |
233 | ); | 224 | ); |
234 | } | 225 | } |
@@ -238,10 +229,10 @@ struct SomeStruct { SomeField: u8 } | |||
238 | check_diagnostics( | 229 | check_diagnostics( |
239 | r#" | 230 | r#" |
240 | enum some_enum { Val(u8) } | 231 | enum some_enum { Val(u8) } |
241 | // ^^^^^^^^^ Enum `some_enum` should have CamelCase name, e.g. `SomeEnum` | 232 | // ^^^^^^^^^ 💡 weak: Enum `some_enum` should have CamelCase name, e.g. `SomeEnum` |
242 | 233 | ||
243 | enum SOME_ENUM {} | 234 | enum SOME_ENUM {} |
244 | // ^^^^^^^^^ Enum `SOME_ENUM` should have CamelCase name, e.g. `SomeEnum` | 235 | // ^^^^^^^^^ 💡 weak: Enum `SOME_ENUM` should have CamelCase name, e.g. `SomeEnum` |
245 | "#, | 236 | "#, |
246 | ); | 237 | ); |
247 | } | 238 | } |
@@ -260,7 +251,7 @@ enum AABB {} | |||
260 | check_diagnostics( | 251 | check_diagnostics( |
261 | r#" | 252 | r#" |
262 | enum SomeEnum { SOME_VARIANT(u8) } | 253 | enum SomeEnum { SOME_VARIANT(u8) } |
263 | // ^^^^^^^^^^^^ Variant `SOME_VARIANT` should have CamelCase name, e.g. `SomeVariant` | 254 | // ^^^^^^^^^^^^ 💡 weak: Variant `SOME_VARIANT` should have CamelCase name, e.g. `SomeVariant` |
264 | "#, | 255 | "#, |
265 | ); | 256 | ); |
266 | } | 257 | } |
@@ -270,7 +261,7 @@ enum SomeEnum { SOME_VARIANT(u8) } | |||
270 | check_diagnostics( | 261 | check_diagnostics( |
271 | r#" | 262 | r#" |
272 | const some_weird_const: u8 = 10; | 263 | const some_weird_const: u8 = 10; |
273 | // ^^^^^^^^^^^^^^^^ Constant `some_weird_const` should have UPPER_SNAKE_CASE name, e.g. `SOME_WEIRD_CONST` | 264 | // ^^^^^^^^^^^^^^^^ 💡 weak: Constant `some_weird_const` should have UPPER_SNAKE_CASE name, e.g. `SOME_WEIRD_CONST` |
274 | "#, | 265 | "#, |
275 | ); | 266 | ); |
276 | } | 267 | } |
@@ -280,7 +271,7 @@ const some_weird_const: u8 = 10; | |||
280 | check_diagnostics( | 271 | check_diagnostics( |
281 | r#" | 272 | r#" |
282 | static some_weird_const: u8 = 10; | 273 | static some_weird_const: u8 = 10; |
283 | // ^^^^^^^^^^^^^^^^ Static variable `some_weird_const` should have UPPER_SNAKE_CASE name, e.g. `SOME_WEIRD_CONST` | 274 | // ^^^^^^^^^^^^^^^^ 💡 weak: Static variable `some_weird_const` should have UPPER_SNAKE_CASE name, e.g. `SOME_WEIRD_CONST` |
284 | "#, | 275 | "#, |
285 | ); | 276 | ); |
286 | } | 277 | } |
@@ -290,13 +281,13 @@ static some_weird_const: u8 = 10; | |||
290 | check_diagnostics( | 281 | check_diagnostics( |
291 | r#" | 282 | r#" |
292 | struct someStruct; | 283 | struct someStruct; |
293 | // ^^^^^^^^^^ Structure `someStruct` should have CamelCase name, e.g. `SomeStruct` | 284 | // ^^^^^^^^^^ 💡 weak: Structure `someStruct` should have CamelCase name, e.g. `SomeStruct` |
294 | 285 | ||
295 | impl someStruct { | 286 | impl someStruct { |
296 | fn SomeFunc(&self) { | 287 | fn SomeFunc(&self) { |
297 | // ^^^^^^^^ Function `SomeFunc` should have snake_case name, e.g. `some_func` | 288 | // ^^^^^^^^ 💡 weak: Function `SomeFunc` should have snake_case name, e.g. `some_func` |
298 | let WHY_VAR_IS_CAPS = 10; | 289 | let WHY_VAR_IS_CAPS = 10; |
299 | // ^^^^^^^^^^^^^^^ Variable `WHY_VAR_IS_CAPS` should have snake_case name, e.g. `why_var_is_caps` | 290 | // ^^^^^^^^^^^^^^^ 💡 weak: Variable `WHY_VAR_IS_CAPS` should have snake_case name, e.g. `why_var_is_caps` |
300 | } | 291 | } |
301 | } | 292 | } |
302 | "#, | 293 | "#, |
@@ -328,7 +319,7 @@ enum Option { Some, None } | |||
328 | fn main() { | 319 | fn main() { |
329 | match Option::None { | 320 | match Option::None { |
330 | SOME_VAR @ None => (), | 321 | SOME_VAR @ None => (), |
331 | // ^^^^^^^^ Variable `SOME_VAR` should have snake_case name, e.g. `some_var` | 322 | // ^^^^^^^^ 💡 weak: Variable `SOME_VAR` should have snake_case name, e.g. `some_var` |
332 | Some => (), | 323 | Some => (), |
333 | } | 324 | } |
334 | } | 325 | } |
@@ -350,43 +341,27 @@ mod F { | |||
350 | } | 341 | } |
351 | 342 | ||
352 | #[test] | 343 | #[test] |
353 | #[ignore] | 344 | fn complex_ignore() { |
354 | fn bug_trait_inside_fn() { | 345 | // FIXME: this should trigger errors for the second case. |
355 | // FIXME: | ||
356 | // This is broken, and in fact, should not even be looked at by this | ||
357 | // lint in the first place. There's weird stuff going on in the | ||
358 | // collection phase. | ||
359 | // It's currently being brought in by: | ||
360 | // * validate_func on `a` recursing into modules | ||
361 | // * then it finds the trait and then the function while iterating | ||
362 | // through modules | ||
363 | // * then validate_func is called on Dirty | ||
364 | // * ... which then proceeds to look at some unknown module taking no | ||
365 | // attrs from either the impl or the fn a, and then finally to the root | ||
366 | // module | ||
367 | // | ||
368 | // It should find the attribute on the trait, but it *doesn't even see | ||
369 | // the trait* as far as I can tell. | ||
370 | |||
371 | check_diagnostics( | 346 | check_diagnostics( |
372 | r#" | 347 | r#" |
373 | trait T { fn a(); } | 348 | trait T { fn a(); } |
374 | struct U {} | 349 | struct U {} |
375 | impl T for U { | 350 | impl T for U { |
376 | fn a() { | 351 | fn a() { |
377 | // this comes out of bitflags, mostly | ||
378 | #[allow(non_snake_case)] | 352 | #[allow(non_snake_case)] |
379 | trait __BitFlags { | 353 | trait __BitFlagsOk { |
380 | const HiImAlsoBad: u8 = 2; | 354 | const HiImAlsoBad: u8 = 2; |
381 | #[inline] | 355 | fn Dirty(&self) -> bool { false } |
382 | fn Dirty(&self) -> bool { | ||
383 | false | ||
384 | } | ||
385 | } | 356 | } |
386 | 357 | ||
358 | trait __BitFlagsBad { | ||
359 | const HiImAlsoBad: u8 = 2; | ||
360 | fn Dirty(&self) -> bool { false } | ||
361 | } | ||
387 | } | 362 | } |
388 | } | 363 | } |
389 | "#, | 364 | "#, |
390 | ); | 365 | ); |
391 | } | 366 | } |
392 | 367 | ||
@@ -423,18 +398,14 @@ extern { | |||
423 | } | 398 | } |
424 | 399 | ||
425 | #[test] | 400 | #[test] |
426 | #[ignore] | ||
427 | fn bug_traits_arent_checked() { | 401 | fn bug_traits_arent_checked() { |
428 | // FIXME: Traits and functions in traits aren't currently checked by | 402 | // FIXME: Traits and functions in traits aren't currently checked by |
429 | // r-a, even though rustc will complain about them. | 403 | // r-a, even though rustc will complain about them. |
430 | check_diagnostics( | 404 | check_diagnostics( |
431 | r#" | 405 | r#" |
432 | trait BAD_TRAIT { | 406 | trait BAD_TRAIT { |
433 | // ^^^^^^^^^ Trait `BAD_TRAIT` should have CamelCase name, e.g. `BadTrait` | ||
434 | fn BAD_FUNCTION(); | 407 | fn BAD_FUNCTION(); |
435 | // ^^^^^^^^^^^^ Function `BAD_FUNCTION` should have snake_case name, e.g. `bad_function` | ||
436 | fn BadFunction(); | 408 | fn BadFunction(); |
437 | // ^^^^^^^^^^^^ Function `BadFunction` should have snake_case name, e.g. `bad_function` | ||
438 | } | 409 | } |
439 | "#, | 410 | "#, |
440 | ); | 411 | ); |
diff --git a/crates/ide/src/diagnostics/macro_error.rs b/crates/ide_diagnostics/src/handlers/macro_error.rs index 5f97f190d..356f089b2 100644 --- a/crates/ide/src/diagnostics/macro_error.rs +++ b/crates/ide_diagnostics/src/handlers/macro_error.rs | |||
@@ -1,9 +1,9 @@ | |||
1 | use crate::diagnostics::{Diagnostic, DiagnosticsContext}; | 1 | use crate::{Diagnostic, DiagnosticsContext}; |
2 | 2 | ||
3 | // Diagnostic: macro-error | 3 | // Diagnostic: macro-error |
4 | // | 4 | // |
5 | // This diagnostic is shown for macro expansion errors. | 5 | // This diagnostic is shown for macro expansion errors. |
6 | pub(super) fn macro_error(ctx: &DiagnosticsContext<'_>, d: &hir::MacroError) -> Diagnostic { | 6 | pub(crate) fn macro_error(ctx: &DiagnosticsContext<'_>, d: &hir::MacroError) -> Diagnostic { |
7 | Diagnostic::new( | 7 | Diagnostic::new( |
8 | "macro-error", | 8 | "macro-error", |
9 | d.message.clone(), | 9 | d.message.clone(), |
@@ -15,7 +15,7 @@ pub(super) fn macro_error(ctx: &DiagnosticsContext<'_>, d: &hir::MacroError) -> | |||
15 | #[cfg(test)] | 15 | #[cfg(test)] |
16 | mod tests { | 16 | mod tests { |
17 | use crate::{ | 17 | use crate::{ |
18 | diagnostics::tests::{check_diagnostics, check_diagnostics_with_config}, | 18 | tests::{check_diagnostics, check_diagnostics_with_config}, |
19 | DiagnosticsConfig, | 19 | DiagnosticsConfig, |
20 | }; | 20 | }; |
21 | 21 | ||
@@ -27,7 +27,7 @@ mod tests { | |||
27 | macro_rules! include { () => {} } | 27 | macro_rules! include { () => {} } |
28 | 28 | ||
29 | include!("doesntexist"); | 29 | include!("doesntexist"); |
30 | //^^^^^^^^^^^^^^^^^^^^^^^^ failed to load file `doesntexist` | 30 | //^^^^^^^^^^^^^^^^^^^^^^^^ error: failed to load file `doesntexist` |
31 | "#, | 31 | "#, |
32 | ); | 32 | ); |
33 | } | 33 | } |
@@ -66,7 +66,7 @@ macro_rules! env { () => {} } | |||
66 | macro_rules! concat { () => {} } | 66 | macro_rules! concat { () => {} } |
67 | 67 | ||
68 | include!(concat!(env!("OUT_DIR"), "/out.rs")); | 68 | include!(concat!(env!("OUT_DIR"), "/out.rs")); |
69 | //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `OUT_DIR` not set, enable "run build scripts" to fix | 69 | //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: `OUT_DIR` not set, enable "run build scripts" to fix |
70 | "#, | 70 | "#, |
71 | ); | 71 | ); |
72 | } | 72 | } |
@@ -108,23 +108,23 @@ fn main() { | |||
108 | // Test a handful of built-in (eager) macros: | 108 | // Test a handful of built-in (eager) macros: |
109 | 109 | ||
110 | include!(invalid); | 110 | include!(invalid); |
111 | //^^^^^^^^^^^^^^^^^ could not convert tokens | 111 | //^^^^^^^^^^^^^^^^^ error: could not convert tokens |
112 | include!("does not exist"); | 112 | include!("does not exist"); |
113 | //^^^^^^^^^^^^^^^^^^^^^^^^^^ failed to load file `does not exist` | 113 | //^^^^^^^^^^^^^^^^^^^^^^^^^^ error: failed to load file `does not exist` |
114 | 114 | ||
115 | env!(invalid); | 115 | env!(invalid); |
116 | //^^^^^^^^^^^^^ could not convert tokens | 116 | //^^^^^^^^^^^^^ error: could not convert tokens |
117 | 117 | ||
118 | env!("OUT_DIR"); | 118 | env!("OUT_DIR"); |
119 | //^^^^^^^^^^^^^^^ `OUT_DIR` not set, enable "run build scripts" to fix | 119 | //^^^^^^^^^^^^^^^ error: `OUT_DIR` not set, enable "run build scripts" to fix |
120 | 120 | ||
121 | compile_error!("compile_error works"); | 121 | compile_error!("compile_error works"); |
122 | //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ compile_error works | 122 | //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: compile_error works |
123 | 123 | ||
124 | // Lazy: | 124 | // Lazy: |
125 | 125 | ||
126 | format_args!(); | 126 | format_args!(); |
127 | //^^^^^^^^^^^^^^ no rule matches input tokens | 127 | //^^^^^^^^^^^^^^ error: no rule matches input tokens |
128 | } | 128 | } |
129 | "#, | 129 | "#, |
130 | ); | 130 | ); |
@@ -141,7 +141,7 @@ fn f() { | |||
141 | m!(); | 141 | m!(); |
142 | 142 | ||
143 | m!(hi); | 143 | m!(hi); |
144 | //^^^^^^ leftover tokens | 144 | //^^^^^^ error: leftover tokens |
145 | } | 145 | } |
146 | "#, | 146 | "#, |
147 | ); | 147 | ); |
@@ -166,7 +166,7 @@ macro_rules! outer { | |||
166 | 166 | ||
167 | fn f() { | 167 | fn f() { |
168 | outer!(); | 168 | outer!(); |
169 | } //^^^^^^^^ leftover tokens | 169 | } //^^^^^^^^ error: leftover tokens |
170 | "#, | 170 | "#, |
171 | ) | 171 | ) |
172 | } | 172 | } |
diff --git a/crates/ide/src/diagnostics/mismatched_arg_count.rs b/crates/ide_diagnostics/src/handlers/mismatched_arg_count.rs index 08e1cfa5f..a9b6d3870 100644 --- a/crates/ide/src/diagnostics/mismatched_arg_count.rs +++ b/crates/ide_diagnostics/src/handlers/mismatched_arg_count.rs | |||
@@ -1,9 +1,9 @@ | |||
1 | use crate::diagnostics::{Diagnostic, DiagnosticsContext}; | 1 | use crate::{Diagnostic, DiagnosticsContext}; |
2 | 2 | ||
3 | // Diagnostic: mismatched-arg-count | 3 | // Diagnostic: mismatched-arg-count |
4 | // | 4 | // |
5 | // This diagnostic is triggered if a function is invoked with an incorrect amount of arguments. | 5 | // This diagnostic is triggered if a function is invoked with an incorrect amount of arguments. |
6 | pub(super) fn mismatched_arg_count( | 6 | pub(crate) fn mismatched_arg_count( |
7 | ctx: &DiagnosticsContext<'_>, | 7 | ctx: &DiagnosticsContext<'_>, |
8 | d: &hir::MismatchedArgCount, | 8 | d: &hir::MismatchedArgCount, |
9 | ) -> Diagnostic { | 9 | ) -> Diagnostic { |
@@ -18,7 +18,7 @@ pub(super) fn mismatched_arg_count( | |||
18 | 18 | ||
19 | #[cfg(test)] | 19 | #[cfg(test)] |
20 | mod tests { | 20 | mod tests { |
21 | use crate::diagnostics::tests::check_diagnostics; | 21 | use crate::tests::check_diagnostics; |
22 | 22 | ||
23 | #[test] | 23 | #[test] |
24 | fn simple_free_fn_zero() { | 24 | fn simple_free_fn_zero() { |
@@ -26,7 +26,7 @@ mod tests { | |||
26 | r#" | 26 | r#" |
27 | fn zero() {} | 27 | fn zero() {} |
28 | fn f() { zero(1); } | 28 | fn f() { zero(1); } |
29 | //^^^^^^^ expected 0 arguments, found 1 | 29 | //^^^^^^^ error: expected 0 arguments, found 1 |
30 | "#, | 30 | "#, |
31 | ); | 31 | ); |
32 | 32 | ||
@@ -44,7 +44,7 @@ fn f() { zero(); } | |||
44 | r#" | 44 | r#" |
45 | fn one(arg: u8) {} | 45 | fn one(arg: u8) {} |
46 | fn f() { one(); } | 46 | fn f() { one(); } |
47 | //^^^^^ expected 1 argument, found 0 | 47 | //^^^^^ error: expected 1 argument, found 0 |
48 | "#, | 48 | "#, |
49 | ); | 49 | ); |
50 | 50 | ||
@@ -65,7 +65,7 @@ impl S { fn method(&self) {} } | |||
65 | 65 | ||
66 | fn f() { | 66 | fn f() { |
67 | S::method(); | 67 | S::method(); |
68 | } //^^^^^^^^^^^ expected 1 argument, found 0 | 68 | } //^^^^^^^^^^^ error: expected 1 argument, found 0 |
69 | "#, | 69 | "#, |
70 | ); | 70 | ); |
71 | 71 | ||
@@ -91,7 +91,7 @@ impl S { fn method(&self, arg: u8) {} } | |||
91 | 91 | ||
92 | fn f() { | 92 | fn f() { |
93 | S.method(); | 93 | S.method(); |
94 | } //^^^^^^^^^^ expected 1 argument, found 0 | 94 | } //^^^^^^^^^^ error: expected 1 argument, found 0 |
95 | "#, | 95 | "#, |
96 | ); | 96 | ); |
97 | 97 | ||
@@ -131,7 +131,7 @@ fn f() { | |||
131 | struct Tup(u8, u16); | 131 | struct Tup(u8, u16); |
132 | fn f() { | 132 | fn f() { |
133 | Tup(0); | 133 | Tup(0); |
134 | } //^^^^^^ expected 2 arguments, found 1 | 134 | } //^^^^^^ error: expected 2 arguments, found 1 |
135 | "#, | 135 | "#, |
136 | ) | 136 | ) |
137 | } | 137 | } |
@@ -143,7 +143,7 @@ fn f() { | |||
143 | enum En { Variant(u8, u16), } | 143 | enum En { Variant(u8, u16), } |
144 | fn f() { | 144 | fn f() { |
145 | En::Variant(0); | 145 | En::Variant(0); |
146 | } //^^^^^^^^^^^^^^ expected 2 arguments, found 1 | 146 | } //^^^^^^^^^^^^^^ error: expected 2 arguments, found 1 |
147 | "#, | 147 | "#, |
148 | ) | 148 | ) |
149 | } | 149 | } |
@@ -162,9 +162,9 @@ impl Foo { | |||
162 | fn new() { | 162 | fn new() { |
163 | Foo::Bar(0); | 163 | Foo::Bar(0); |
164 | Foo::Bar(0, 1); | 164 | Foo::Bar(0, 1); |
165 | //^^^^^^^^^^^^^^ expected 1 argument, found 2 | 165 | //^^^^^^^^^^^^^^ error: expected 1 argument, found 2 |
166 | Foo::Bar(); | 166 | Foo::Bar(); |
167 | //^^^^^^^^^^ expected 1 argument, found 0 | 167 | //^^^^^^^^^^ error: expected 1 argument, found 0 |
168 | } | 168 | } |
169 | } | 169 | } |
170 | "#, | 170 | "#, |
@@ -185,7 +185,7 @@ fn f() { | |||
185 | unsafe { | 185 | unsafe { |
186 | fixed(0); | 186 | fixed(0); |
187 | fixed(0, 1); | 187 | fixed(0, 1); |
188 | //^^^^^^^^^^^ expected 1 argument, found 2 | 188 | //^^^^^^^^^^^ error: expected 1 argument, found 2 |
189 | varargs(0); | 189 | varargs(0); |
190 | varargs(0, 1); | 190 | varargs(0, 1); |
191 | varargs2(); | 191 | varargs2(); |
@@ -204,10 +204,10 @@ fn f() { | |||
204 | fn main() { | 204 | fn main() { |
205 | let f = |()| (); | 205 | let f = |()| (); |
206 | f(); | 206 | f(); |
207 | //^^^ expected 1 argument, found 0 | 207 | //^^^ error: expected 1 argument, found 0 |
208 | f(()); | 208 | f(()); |
209 | f((), ()); | 209 | f((), ()); |
210 | //^^^^^^^^^ expected 1 argument, found 2 | 210 | //^^^^^^^^^ error: expected 1 argument, found 2 |
211 | } | 211 | } |
212 | "#, | 212 | "#, |
213 | ) | 213 | ) |
diff --git a/crates/ide/src/diagnostics/missing_fields.rs b/crates/ide_diagnostics/src/handlers/missing_fields.rs index d01f05041..bc56e0342 100644 --- a/crates/ide/src/diagnostics/missing_fields.rs +++ b/crates/ide_diagnostics/src/handlers/missing_fields.rs | |||
@@ -1,12 +1,11 @@ | |||
1 | use either::Either; | 1 | use either::Either; |
2 | use hir::{db::AstDatabase, InFile}; | 2 | use hir::{db::AstDatabase, InFile}; |
3 | use ide_assists::Assist; | 3 | use ide_db::{assists::Assist, source_change::SourceChange}; |
4 | use ide_db::source_change::SourceChange; | ||
5 | use stdx::format_to; | 4 | use stdx::format_to; |
6 | use syntax::{algo, ast::make, AstNode, SyntaxNodePtr}; | 5 | use syntax::{algo, ast::make, AstNode, SyntaxNodePtr}; |
7 | use text_edit::TextEdit; | 6 | use text_edit::TextEdit; |
8 | 7 | ||
9 | use crate::diagnostics::{fix, Diagnostic, DiagnosticsContext}; | 8 | use crate::{fix, Diagnostic, DiagnosticsContext}; |
10 | 9 | ||
11 | // Diagnostic: missing-fields | 10 | // Diagnostic: missing-fields |
12 | // | 11 | // |
@@ -19,8 +18,8 @@ use crate::diagnostics::{fix, Diagnostic, DiagnosticsContext}; | |||
19 | // | 18 | // |
20 | // let a = A { a: 10 }; | 19 | // let a = A { a: 10 }; |
21 | // ``` | 20 | // ``` |
22 | pub(super) fn missing_fields(ctx: &DiagnosticsContext<'_>, d: &hir::MissingFields) -> Diagnostic { | 21 | pub(crate) fn missing_fields(ctx: &DiagnosticsContext<'_>, d: &hir::MissingFields) -> Diagnostic { |
23 | let mut message = String::from("Missing structure fields:\n"); | 22 | let mut message = String::from("missing structure fields:\n"); |
24 | for field in &d.missed_fields { | 23 | for field in &d.missed_fields { |
25 | format_to!(message, "- {}\n", field); | 24 | format_to!(message, "- {}\n", field); |
26 | } | 25 | } |
@@ -77,7 +76,7 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::MissingFields) -> Option<Vec<Ass | |||
77 | 76 | ||
78 | #[cfg(test)] | 77 | #[cfg(test)] |
79 | mod tests { | 78 | mod tests { |
80 | use crate::diagnostics::tests::{check_diagnostics, check_fix}; | 79 | use crate::tests::{check_diagnostics, check_fix}; |
81 | 80 | ||
82 | #[test] | 81 | #[test] |
83 | fn missing_record_pat_field_diagnostic() { | 82 | fn missing_record_pat_field_diagnostic() { |
@@ -86,7 +85,7 @@ mod tests { | |||
86 | struct S { foo: i32, bar: () } | 85 | struct S { foo: i32, bar: () } |
87 | fn baz(s: S) { | 86 | fn baz(s: S) { |
88 | let S { foo: _ } = s; | 87 | let S { foo: _ } = s; |
89 | //^ Missing structure fields: | 88 | //^ error: missing structure fields: |
90 | //| - bar | 89 | //| - bar |
91 | } | 90 | } |
92 | "#, | 91 | "#, |
@@ -324,4 +323,33 @@ fn f() { | |||
324 | "#, | 323 | "#, |
325 | ); | 324 | ); |
326 | } | 325 | } |
326 | |||
327 | #[test] | ||
328 | fn import_extern_crate_clash_with_inner_item() { | ||
329 | // This is more of a resolver test, but doesn't really work with the hir_def testsuite. | ||
330 | |||
331 | check_diagnostics( | ||
332 | r#" | ||
333 | //- /lib.rs crate:lib deps:jwt | ||
334 | mod permissions; | ||
335 | |||
336 | use permissions::jwt; | ||
337 | |||
338 | fn f() { | ||
339 | fn inner() {} | ||
340 | jwt::Claims {}; // should resolve to the local one with 0 fields, and not get a diagnostic | ||
341 | } | ||
342 | |||
343 | //- /permissions.rs | ||
344 | pub mod jwt { | ||
345 | pub struct Claims {} | ||
346 | } | ||
347 | |||
348 | //- /jwt/lib.rs crate:jwt | ||
349 | pub struct Claims { | ||
350 | field: u8, | ||
351 | } | ||
352 | "#, | ||
353 | ); | ||
354 | } | ||
327 | } | 355 | } |
diff --git a/crates/ide/src/diagnostics/missing_match_arms.rs b/crates/ide_diagnostics/src/handlers/missing_match_arms.rs index b636489b3..947b0f2e2 100644 --- a/crates/ide/src/diagnostics/missing_match_arms.rs +++ b/crates/ide_diagnostics/src/handlers/missing_match_arms.rs | |||
@@ -1,11 +1,11 @@ | |||
1 | use hir::InFile; | 1 | use hir::InFile; |
2 | 2 | ||
3 | use crate::diagnostics::{Diagnostic, DiagnosticsContext}; | 3 | use crate::{Diagnostic, DiagnosticsContext}; |
4 | 4 | ||
5 | // Diagnostic: missing-match-arm | 5 | // Diagnostic: missing-match-arm |
6 | // | 6 | // |
7 | // This diagnostic is triggered if `match` block is missing one or more match arms. | 7 | // This diagnostic is triggered if `match` block is missing one or more match arms. |
8 | pub(super) fn missing_match_arms( | 8 | pub(crate) fn missing_match_arms( |
9 | ctx: &DiagnosticsContext<'_>, | 9 | ctx: &DiagnosticsContext<'_>, |
10 | d: &hir::MissingMatchArms, | 10 | d: &hir::MissingMatchArms, |
11 | ) -> Diagnostic { | 11 | ) -> Diagnostic { |
@@ -17,12 +17,12 @@ pub(super) fn missing_match_arms( | |||
17 | } | 17 | } |
18 | 18 | ||
19 | #[cfg(test)] | 19 | #[cfg(test)] |
20 | pub(super) mod tests { | 20 | mod tests { |
21 | use crate::diagnostics::tests::check_diagnostics; | 21 | use crate::tests::check_diagnostics; |
22 | 22 | ||
23 | fn check_diagnostics_no_bails(ra_fixture: &str) { | 23 | fn check_diagnostics_no_bails(ra_fixture: &str) { |
24 | cov_mark::check_count!(validate_match_bailed_out, 0); | 24 | cov_mark::check_count!(validate_match_bailed_out, 0); |
25 | crate::diagnostics::tests::check_diagnostics(ra_fixture) | 25 | crate::tests::check_diagnostics(ra_fixture) |
26 | } | 26 | } |
27 | 27 | ||
28 | #[test] | 28 | #[test] |
@@ -31,9 +31,9 @@ pub(super) mod tests { | |||
31 | r#" | 31 | r#" |
32 | fn main() { | 32 | fn main() { |
33 | match () { } | 33 | match () { } |
34 | //^^ missing match arm | 34 | //^^ error: missing match arm |
35 | match (()) { } | 35 | match (()) { } |
36 | //^^^^ missing match arm | 36 | //^^^^ error: missing match arm |
37 | 37 | ||
38 | match () { _ => (), } | 38 | match () { _ => (), } |
39 | match () { () => (), } | 39 | match () { () => (), } |
@@ -49,7 +49,7 @@ fn main() { | |||
49 | r#" | 49 | r#" |
50 | fn main() { | 50 | fn main() { |
51 | match ((), ()) { } | 51 | match ((), ()) { } |
52 | //^^^^^^^^ missing match arm | 52 | //^^^^^^^^ error: missing match arm |
53 | 53 | ||
54 | match ((), ()) { ((), ()) => (), } | 54 | match ((), ()) { ((), ()) => (), } |
55 | } | 55 | } |
@@ -63,21 +63,21 @@ fn main() { | |||
63 | r#" | 63 | r#" |
64 | fn test_main() { | 64 | fn test_main() { |
65 | match false { } | 65 | match false { } |
66 | //^^^^^ missing match arm | 66 | //^^^^^ error: missing match arm |
67 | match false { true => (), } | 67 | match false { true => (), } |
68 | //^^^^^ missing match arm | 68 | //^^^^^ error: missing match arm |
69 | match (false, true) {} | 69 | match (false, true) {} |
70 | //^^^^^^^^^^^^^ missing match arm | 70 | //^^^^^^^^^^^^^ error: missing match arm |
71 | match (false, true) { (true, true) => (), } | 71 | match (false, true) { (true, true) => (), } |
72 | //^^^^^^^^^^^^^ missing match arm | 72 | //^^^^^^^^^^^^^ error: missing match arm |
73 | match (false, true) { | 73 | match (false, true) { |
74 | //^^^^^^^^^^^^^ missing match arm | 74 | //^^^^^^^^^^^^^ error: missing match arm |
75 | (false, true) => (), | 75 | (false, true) => (), |
76 | (false, false) => (), | 76 | (false, false) => (), |
77 | (true, false) => (), | 77 | (true, false) => (), |
78 | } | 78 | } |
79 | match (false, true) { (true, _x) => (), } | 79 | match (false, true) { (true, _x) => (), } |
80 | //^^^^^^^^^^^^^ missing match arm | 80 | //^^^^^^^^^^^^^ error: missing match arm |
81 | 81 | ||
82 | match false { true => (), false => (), } | 82 | match false { true => (), false => (), } |
83 | match (false, true) { | 83 | match (false, true) { |
@@ -116,11 +116,11 @@ fn test_main() { | |||
116 | r#" | 116 | r#" |
117 | fn main() { | 117 | fn main() { |
118 | match (false, ((), false)) {} | 118 | match (false, ((), false)) {} |
119 | //^^^^^^^^^^^^^^^^^^^^ missing match arm | 119 | //^^^^^^^^^^^^^^^^^^^^ error: missing match arm |
120 | match (false, ((), false)) { (true, ((), true)) => (), } | 120 | match (false, ((), false)) { (true, ((), true)) => (), } |
121 | //^^^^^^^^^^^^^^^^^^^^ missing match arm | 121 | //^^^^^^^^^^^^^^^^^^^^ error: missing match arm |
122 | match (false, ((), false)) { (true, _) => (), } | 122 | match (false, ((), false)) { (true, _) => (), } |
123 | //^^^^^^^^^^^^^^^^^^^^ missing match arm | 123 | //^^^^^^^^^^^^^^^^^^^^ error: missing match arm |
124 | 124 | ||
125 | match (false, ((), false)) { | 125 | match (false, ((), false)) { |
126 | (true, ((), true)) => (), | 126 | (true, ((), true)) => (), |
@@ -146,12 +146,12 @@ enum Either { A, B, } | |||
146 | 146 | ||
147 | fn main() { | 147 | fn main() { |
148 | match Either::A { } | 148 | match Either::A { } |
149 | //^^^^^^^^^ missing match arm | 149 | //^^^^^^^^^ error: missing match arm |
150 | match Either::B { Either::A => (), } | 150 | match Either::B { Either::A => (), } |
151 | //^^^^^^^^^ missing match arm | 151 | //^^^^^^^^^ error: missing match arm |
152 | 152 | ||
153 | match &Either::B { | 153 | match &Either::B { |
154 | //^^^^^^^^^^ missing match arm | 154 | //^^^^^^^^^^ error: missing match arm |
155 | Either::A => (), | 155 | Either::A => (), |
156 | } | 156 | } |
157 | 157 | ||
@@ -174,9 +174,9 @@ enum Either { A(bool), B } | |||
174 | 174 | ||
175 | fn main() { | 175 | fn main() { |
176 | match Either::B { } | 176 | match Either::B { } |
177 | //^^^^^^^^^ missing match arm | 177 | //^^^^^^^^^ error: missing match arm |
178 | match Either::B { | 178 | match Either::B { |
179 | //^^^^^^^^^ missing match arm | 179 | //^^^^^^^^^ error: missing match arm |
180 | Either::A(true) => (), Either::B => () | 180 | Either::A(true) => (), Either::B => () |
181 | } | 181 | } |
182 | 182 | ||
@@ -207,7 +207,7 @@ enum Either { A(bool), B(bool, bool) } | |||
207 | 207 | ||
208 | fn main() { | 208 | fn main() { |
209 | match Either::A(false) { | 209 | match Either::A(false) { |
210 | //^^^^^^^^^^^^^^^^ missing match arm | 210 | //^^^^^^^^^^^^^^^^ error: missing match arm |
211 | Either::A(_) => (), | 211 | Either::A(_) => (), |
212 | Either::B(false, _) => (), | 212 | Either::B(false, _) => (), |
213 | } | 213 | } |
@@ -352,7 +352,7 @@ fn main() { | |||
352 | Either::A => (), | 352 | Either::A => (), |
353 | } | 353 | } |
354 | match loop { break Foo::A } { | 354 | match loop { break Foo::A } { |
355 | //^^^^^^^^^^^^^^^^^^^^^ missing match arm | 355 | //^^^^^^^^^^^^^^^^^^^^^ error: missing match arm |
356 | Either::A => (), | 356 | Either::A => (), |
357 | } | 357 | } |
358 | match loop { break Foo::A } { | 358 | match loop { break Foo::A } { |
@@ -390,19 +390,19 @@ enum Either { A { foo: bool }, B } | |||
390 | fn main() { | 390 | fn main() { |
391 | let a = Either::A { foo: true }; | 391 | let a = Either::A { foo: true }; |
392 | match a { } | 392 | match a { } |
393 | //^ missing match arm | 393 | //^ error: missing match arm |
394 | match a { Either::A { foo: true } => () } | 394 | match a { Either::A { foo: true } => () } |
395 | //^ missing match arm | 395 | //^ error: missing match arm |
396 | match a { | 396 | match a { |
397 | Either::A { } => (), | 397 | Either::A { } => (), |
398 | //^^^^^^^^^ Missing structure fields: | 398 | //^^^^^^^^^ error: missing structure fields: |
399 | // | - foo | 399 | // | - foo |
400 | Either::B => (), | 400 | Either::B => (), |
401 | } | 401 | } |
402 | match a { | 402 | match a { |
403 | //^ missing match arm | 403 | //^ error: missing match arm |
404 | Either::A { } => (), | 404 | Either::A { } => (), |
405 | } //^^^^^^^^^ Missing structure fields: | 405 | } //^^^^^^^^^ error: missing structure fields: |
406 | // | - foo | 406 | // | - foo |
407 | 407 | ||
408 | match a { | 408 | match a { |
@@ -431,7 +431,7 @@ enum Either { | |||
431 | fn main() { | 431 | fn main() { |
432 | let a = Either::A { foo: true, bar: () }; | 432 | let a = Either::A { foo: true, bar: () }; |
433 | match a { | 433 | match a { |
434 | //^ missing match arm | 434 | //^ error: missing match arm |
435 | Either::A { bar: (), foo: false } => (), | 435 | Either::A { bar: (), foo: false } => (), |
436 | Either::A { foo: true, bar: () } => (), | 436 | Either::A { foo: true, bar: () } => (), |
437 | } | 437 | } |
@@ -458,12 +458,12 @@ enum Either { | |||
458 | fn main() { | 458 | fn main() { |
459 | let a = Either::B; | 459 | let a = Either::B; |
460 | match a { | 460 | match a { |
461 | //^ missing match arm | 461 | //^ error: missing match arm |
462 | Either::A { foo: true, .. } => (), | 462 | Either::A { foo: true, .. } => (), |
463 | Either::B => (), | 463 | Either::B => (), |
464 | } | 464 | } |
465 | match a { | 465 | match a { |
466 | //^ missing match arm | 466 | //^ error: missing match arm |
467 | Either::A { .. } => (), | 467 | Either::A { .. } => (), |
468 | } | 468 | } |
469 | 469 | ||
@@ -493,14 +493,14 @@ enum Either { | |||
493 | 493 | ||
494 | fn main() { | 494 | fn main() { |
495 | match Either::B { | 495 | match Either::B { |
496 | //^^^^^^^^^ missing match arm | 496 | //^^^^^^^^^ error: missing match arm |
497 | Either::A(true, .., true) => (), | 497 | Either::A(true, .., true) => (), |
498 | Either::A(true, .., false) => (), | 498 | Either::A(true, .., false) => (), |
499 | Either::A(false, .., false) => (), | 499 | Either::A(false, .., false) => (), |
500 | Either::B => (), | 500 | Either::B => (), |
501 | } | 501 | } |
502 | match Either::B { | 502 | match Either::B { |
503 | //^^^^^^^^^ missing match arm | 503 | //^^^^^^^^^ error: missing match arm |
504 | Either::A(true, .., true) => (), | 504 | Either::A(true, .., true) => (), |
505 | Either::A(true, .., false) => (), | 505 | Either::A(true, .., false) => (), |
506 | Either::A(.., true) => (), | 506 | Either::A(.., true) => (), |
@@ -537,7 +537,7 @@ fn enum_(never: Never) { | |||
537 | } | 537 | } |
538 | fn enum_ref(never: &Never) { | 538 | fn enum_ref(never: &Never) { |
539 | match never {} | 539 | match never {} |
540 | //^^^^^ missing match arm | 540 | //^^^^^ error: missing match arm |
541 | } | 541 | } |
542 | fn bang(never: !) { | 542 | fn bang(never: !) { |
543 | match never {} | 543 | match never {} |
@@ -561,7 +561,7 @@ fn main() { | |||
561 | Some(never) => match never {}, | 561 | Some(never) => match never {}, |
562 | } | 562 | } |
563 | match Option::<Never>::None { | 563 | match Option::<Never>::None { |
564 | //^^^^^^^^^^^^^^^^^^^^^ missing match arm | 564 | //^^^^^^^^^^^^^^^^^^^^^ error: missing match arm |
565 | Option::Some(_never) => {}, | 565 | Option::Some(_never) => {}, |
566 | } | 566 | } |
567 | } | 567 | } |
@@ -575,7 +575,7 @@ fn main() { | |||
575 | r#" | 575 | r#" |
576 | fn main() { | 576 | fn main() { |
577 | match (false, true, false) { | 577 | match (false, true, false) { |
578 | //^^^^^^^^^^^^^^^^^^^^ missing match arm | 578 | //^^^^^^^^^^^^^^^^^^^^ error: missing match arm |
579 | (false, ..) => (), | 579 | (false, ..) => (), |
580 | } | 580 | } |
581 | }"#, | 581 | }"#, |
@@ -588,7 +588,7 @@ fn main() { | |||
588 | r#" | 588 | r#" |
589 | fn main() { | 589 | fn main() { |
590 | match (false, true, false) { | 590 | match (false, true, false) { |
591 | //^^^^^^^^^^^^^^^^^^^^ missing match arm | 591 | //^^^^^^^^^^^^^^^^^^^^ error: missing match arm |
592 | (.., false) => (), | 592 | (.., false) => (), |
593 | } | 593 | } |
594 | }"#, | 594 | }"#, |
@@ -601,7 +601,7 @@ fn main() { | |||
601 | r#" | 601 | r#" |
602 | fn main() { | 602 | fn main() { |
603 | match (false, true, false) { | 603 | match (false, true, false) { |
604 | //^^^^^^^^^^^^^^^^^^^^ missing match arm | 604 | //^^^^^^^^^^^^^^^^^^^^ error: missing match arm |
605 | (true, .., false) => (), | 605 | (true, .., false) => (), |
606 | } | 606 | } |
607 | }"#, | 607 | }"#, |
@@ -614,11 +614,11 @@ fn main() { | |||
614 | r#"struct Foo { a: bool } | 614 | r#"struct Foo { a: bool } |
615 | fn main(f: Foo) { | 615 | fn main(f: Foo) { |
616 | match f {} | 616 | match f {} |
617 | //^ missing match arm | 617 | //^ error: missing match arm |
618 | match f { Foo { a: true } => () } | 618 | match f { Foo { a: true } => () } |
619 | //^ missing match arm | 619 | //^ error: missing match arm |
620 | match &f { Foo { a: true } => () } | 620 | match &f { Foo { a: true } => () } |
621 | //^^ missing match arm | 621 | //^^ error: missing match arm |
622 | match f { Foo { a: _ } => () } | 622 | match f { Foo { a: _ } => () } |
623 | match f { | 623 | match f { |
624 | Foo { a: true } => (), | 624 | Foo { a: true } => (), |
@@ -639,9 +639,9 @@ fn main(f: Foo) { | |||
639 | r#"struct Foo(bool); | 639 | r#"struct Foo(bool); |
640 | fn main(f: Foo) { | 640 | fn main(f: Foo) { |
641 | match f {} | 641 | match f {} |
642 | //^ missing match arm | 642 | //^ error: missing match arm |
643 | match f { Foo(true) => () } | 643 | match f { Foo(true) => () } |
644 | //^ missing match arm | 644 | //^ error: missing match arm |
645 | match f { | 645 | match f { |
646 | Foo(true) => (), | 646 | Foo(true) => (), |
647 | Foo(false) => (), | 647 | Foo(false) => (), |
@@ -657,7 +657,7 @@ fn main(f: Foo) { | |||
657 | r#"struct Foo; | 657 | r#"struct Foo; |
658 | fn main(f: Foo) { | 658 | fn main(f: Foo) { |
659 | match f {} | 659 | match f {} |
660 | //^ missing match arm | 660 | //^ error: missing match arm |
661 | match f { Foo => () } | 661 | match f { Foo => () } |
662 | } | 662 | } |
663 | "#, | 663 | "#, |
@@ -670,9 +670,9 @@ fn main(f: Foo) { | |||
670 | r#"struct Foo { foo: bool, bar: bool } | 670 | r#"struct Foo { foo: bool, bar: bool } |
671 | fn main(f: Foo) { | 671 | fn main(f: Foo) { |
672 | match f { Foo { foo: true, .. } => () } | 672 | match f { Foo { foo: true, .. } => () } |
673 | //^ missing match arm | 673 | //^ error: missing match arm |
674 | match f { | 674 | match f { |
675 | //^ missing match arm | 675 | //^ error: missing match arm |
676 | Foo { foo: true, .. } => (), | 676 | Foo { foo: true, .. } => (), |
677 | Foo { bar: false, .. } => () | 677 | Foo { bar: false, .. } => () |
678 | } | 678 | } |
@@ -693,7 +693,7 @@ fn main(f: Foo) { | |||
693 | fn main() { | 693 | fn main() { |
694 | enum Either { A(bool), B } | 694 | enum Either { A(bool), B } |
695 | match Either::B { | 695 | match Either::B { |
696 | //^^^^^^^^^ missing match arm | 696 | //^^^^^^^^^ error: missing match arm |
697 | Either::A(true | false) => (), | 697 | Either::A(true | false) => (), |
698 | } | 698 | } |
699 | } | 699 | } |
@@ -715,7 +715,7 @@ fn main(v: S) { | |||
715 | match v { S{..} => {} } | 715 | match v { S{..} => {} } |
716 | match v { _ => {} } | 716 | match v { _ => {} } |
717 | match v { } | 717 | match v { } |
718 | //^ missing match arm | 718 | //^ error: missing match arm |
719 | } | 719 | } |
720 | "#, | 720 | "#, |
721 | ); | 721 | ); |
@@ -731,7 +731,7 @@ fn main() { | |||
731 | false => {} | 731 | false => {} |
732 | } | 732 | } |
733 | match true { _x @ true => {} } | 733 | match true { _x @ true => {} } |
734 | //^^^^ missing match arm | 734 | //^^^^ error: missing match arm |
735 | } | 735 | } |
736 | "#, | 736 | "#, |
737 | ); | 737 | ); |
@@ -786,12 +786,12 @@ use lib::E; | |||
786 | fn main() { | 786 | fn main() { |
787 | match E::A { _ => {} } | 787 | match E::A { _ => {} } |
788 | match E::A { | 788 | match E::A { |
789 | //^^^^ missing match arm | 789 | //^^^^ error: missing match arm |
790 | E::A => {} | 790 | E::A => {} |
791 | E::B => {} | 791 | E::B => {} |
792 | } | 792 | } |
793 | match E::A { | 793 | match E::A { |
794 | //^^^^ missing match arm | 794 | //^^^^ error: missing match arm |
795 | E::A | E::B => {} | 795 | E::A | E::B => {} |
796 | } | 796 | } |
797 | } | 797 | } |
@@ -810,7 +810,7 @@ fn main() { | |||
810 | false => {} | 810 | false => {} |
811 | } | 811 | } |
812 | match true { | 812 | match true { |
813 | //^^^^ missing match arm | 813 | //^^^^ error: missing match arm |
814 | true if false => {} | 814 | true if false => {} |
815 | false => {} | 815 | false => {} |
816 | } | 816 | } |
diff --git a/crates/ide/src/diagnostics/missing_ok_or_some_in_tail_expr.rs b/crates/ide_diagnostics/src/handlers/missing_ok_or_some_in_tail_expr.rs index 06005d156..63de54570 100644 --- a/crates/ide/src/diagnostics/missing_ok_or_some_in_tail_expr.rs +++ b/crates/ide_diagnostics/src/handlers/missing_ok_or_some_in_tail_expr.rs | |||
@@ -1,10 +1,9 @@ | |||
1 | use hir::db::AstDatabase; | 1 | use hir::db::AstDatabase; |
2 | use ide_assists::Assist; | 2 | use ide_db::{assists::Assist, source_change::SourceChange}; |
3 | use ide_db::source_change::SourceChange; | ||
4 | use syntax::AstNode; | 3 | use syntax::AstNode; |
5 | use text_edit::TextEdit; | 4 | use text_edit::TextEdit; |
6 | 5 | ||
7 | use crate::diagnostics::{fix, Diagnostic, DiagnosticsContext}; | 6 | use crate::{fix, Diagnostic, DiagnosticsContext}; |
8 | 7 | ||
9 | // Diagnostic: missing-ok-or-some-in-tail-expr | 8 | // Diagnostic: missing-ok-or-some-in-tail-expr |
10 | // | 9 | // |
@@ -18,7 +17,7 @@ use crate::diagnostics::{fix, Diagnostic, DiagnosticsContext}; | |||
18 | // 10 | 17 | // 10 |
19 | // } | 18 | // } |
20 | // ``` | 19 | // ``` |
21 | pub(super) fn missing_ok_or_some_in_tail_expr( | 20 | pub(crate) fn missing_ok_or_some_in_tail_expr( |
22 | ctx: &DiagnosticsContext<'_>, | 21 | ctx: &DiagnosticsContext<'_>, |
23 | d: &hir::MissingOkOrSomeInTailExpr, | 22 | d: &hir::MissingOkOrSomeInTailExpr, |
24 | ) -> Diagnostic { | 23 | ) -> Diagnostic { |
@@ -44,7 +43,7 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::MissingOkOrSomeInTailExpr) -> Op | |||
44 | 43 | ||
45 | #[cfg(test)] | 44 | #[cfg(test)] |
46 | mod tests { | 45 | mod tests { |
47 | use crate::diagnostics::tests::{check_diagnostics, check_fix}; | 46 | use crate::tests::{check_diagnostics, check_fix}; |
48 | 47 | ||
49 | #[test] | 48 | #[test] |
50 | fn test_wrap_return_type_option() { | 49 | fn test_wrap_return_type_option() { |
diff --git a/crates/ide/src/diagnostics/missing_unsafe.rs b/crates/ide_diagnostics/src/handlers/missing_unsafe.rs index 5c47e8d0a..7acd9228a 100644 --- a/crates/ide/src/diagnostics/missing_unsafe.rs +++ b/crates/ide_diagnostics/src/handlers/missing_unsafe.rs | |||
@@ -1,9 +1,9 @@ | |||
1 | use crate::diagnostics::{Diagnostic, DiagnosticsContext}; | 1 | use crate::{Diagnostic, DiagnosticsContext}; |
2 | 2 | ||
3 | // Diagnostic: missing-unsafe | 3 | // Diagnostic: missing-unsafe |
4 | // | 4 | // |
5 | // This diagnostic is triggered if an operation marked as `unsafe` is used outside of an `unsafe` function or block. | 5 | // This diagnostic is triggered if an operation marked as `unsafe` is used outside of an `unsafe` function or block. |
6 | pub(super) fn missing_unsafe(ctx: &DiagnosticsContext<'_>, d: &hir::MissingUnsafe) -> Diagnostic { | 6 | pub(crate) fn missing_unsafe(ctx: &DiagnosticsContext<'_>, d: &hir::MissingUnsafe) -> Diagnostic { |
7 | Diagnostic::new( | 7 | Diagnostic::new( |
8 | "missing-unsafe", | 8 | "missing-unsafe", |
9 | "this operation is unsafe and requires an unsafe function or block", | 9 | "this operation is unsafe and requires an unsafe function or block", |
@@ -13,7 +13,7 @@ pub(super) fn missing_unsafe(ctx: &DiagnosticsContext<'_>, d: &hir::MissingUnsaf | |||
13 | 13 | ||
14 | #[cfg(test)] | 14 | #[cfg(test)] |
15 | mod tests { | 15 | mod tests { |
16 | use crate::diagnostics::tests::check_diagnostics; | 16 | use crate::tests::check_diagnostics; |
17 | 17 | ||
18 | #[test] | 18 | #[test] |
19 | fn missing_unsafe_diagnostic_with_raw_ptr() { | 19 | fn missing_unsafe_diagnostic_with_raw_ptr() { |
@@ -23,7 +23,7 @@ fn main() { | |||
23 | let x = &5 as *const usize; | 23 | let x = &5 as *const usize; |
24 | unsafe { let y = *x; } | 24 | unsafe { let y = *x; } |
25 | let z = *x; | 25 | let z = *x; |
26 | } //^^ this operation is unsafe and requires an unsafe function or block | 26 | } //^^ error: this operation is unsafe and requires an unsafe function or block |
27 | "#, | 27 | "#, |
28 | ) | 28 | ) |
29 | } | 29 | } |
@@ -48,9 +48,9 @@ unsafe fn unsafe_fn() { | |||
48 | 48 | ||
49 | fn main() { | 49 | fn main() { |
50 | unsafe_fn(); | 50 | unsafe_fn(); |
51 | //^^^^^^^^^^^ this operation is unsafe and requires an unsafe function or block | 51 | //^^^^^^^^^^^ error: this operation is unsafe and requires an unsafe function or block |
52 | HasUnsafe.unsafe_fn(); | 52 | HasUnsafe.unsafe_fn(); |
53 | //^^^^^^^^^^^^^^^^^^^^^ this operation is unsafe and requires an unsafe function or block | 53 | //^^^^^^^^^^^^^^^^^^^^^ error: this operation is unsafe and requires an unsafe function or block |
54 | unsafe { | 54 | unsafe { |
55 | unsafe_fn(); | 55 | unsafe_fn(); |
56 | HasUnsafe.unsafe_fn(); | 56 | HasUnsafe.unsafe_fn(); |
@@ -72,7 +72,7 @@ static mut STATIC_MUT: Ty = Ty { a: 0 }; | |||
72 | 72 | ||
73 | fn main() { | 73 | fn main() { |
74 | let x = STATIC_MUT.a; | 74 | let x = STATIC_MUT.a; |
75 | //^^^^^^^^^^ this operation is unsafe and requires an unsafe function or block | 75 | //^^^^^^^^^^ error: this operation is unsafe and requires an unsafe function or block |
76 | unsafe { | 76 | unsafe { |
77 | let x = STATIC_MUT.a; | 77 | let x = STATIC_MUT.a; |
78 | } | 78 | } |
@@ -93,7 +93,7 @@ extern "rust-intrinsic" { | |||
93 | fn main() { | 93 | fn main() { |
94 | let _ = bitreverse(12); | 94 | let _ = bitreverse(12); |
95 | let _ = floorf32(12.0); | 95 | let _ = floorf32(12.0); |
96 | //^^^^^^^^^^^^^^ this operation is unsafe and requires an unsafe function or block | 96 | //^^^^^^^^^^^^^^ error: this operation is unsafe and requires an unsafe function or block |
97 | } | 97 | } |
98 | "#, | 98 | "#, |
99 | ); | 99 | ); |
diff --git a/crates/ide/src/diagnostics/no_such_field.rs b/crates/ide_diagnostics/src/handlers/no_such_field.rs index edc63c246..92e8867f4 100644 --- a/crates/ide/src/diagnostics/no_such_field.rs +++ b/crates/ide_diagnostics/src/handlers/no_such_field.rs | |||
@@ -6,15 +6,12 @@ use syntax::{ | |||
6 | }; | 6 | }; |
7 | use text_edit::TextEdit; | 7 | use text_edit::TextEdit; |
8 | 8 | ||
9 | use crate::{ | 9 | use crate::{fix, Assist, Diagnostic, DiagnosticsContext}; |
10 | diagnostics::{fix, Diagnostic, DiagnosticsContext}, | ||
11 | Assist, | ||
12 | }; | ||
13 | 10 | ||
14 | // Diagnostic: no-such-field | 11 | // Diagnostic: no-such-field |
15 | // | 12 | // |
16 | // This diagnostic is triggered if created structure does not have field provided in record. | 13 | // This diagnostic is triggered if created structure does not have field provided in record. |
17 | pub(super) fn no_such_field(ctx: &DiagnosticsContext<'_>, d: &hir::NoSuchField) -> Diagnostic { | 14 | pub(crate) fn no_such_field(ctx: &DiagnosticsContext<'_>, d: &hir::NoSuchField) -> Diagnostic { |
18 | Diagnostic::new( | 15 | Diagnostic::new( |
19 | "no-such-field", | 16 | "no-such-field", |
20 | "no such field", | 17 | "no such field", |
@@ -112,7 +109,7 @@ fn missing_record_expr_field_fixes( | |||
112 | 109 | ||
113 | #[cfg(test)] | 110 | #[cfg(test)] |
114 | mod tests { | 111 | mod tests { |
115 | use crate::diagnostics::tests::{check_diagnostics, check_fix}; | 112 | use crate::tests::{check_diagnostics, check_fix}; |
116 | 113 | ||
117 | #[test] | 114 | #[test] |
118 | fn no_such_field_diagnostics() { | 115 | fn no_such_field_diagnostics() { |
@@ -122,11 +119,11 @@ struct S { foo: i32, bar: () } | |||
122 | impl S { | 119 | impl S { |
123 | fn new() -> S { | 120 | fn new() -> S { |
124 | S { | 121 | S { |
125 | //^ Missing structure fields: | 122 | //^ 💡 error: missing structure fields: |
126 | //| - bar | 123 | //| - bar |
127 | foo: 92, | 124 | foo: 92, |
128 | baz: 62, | 125 | baz: 62, |
129 | //^^^^^^^ no such field | 126 | //^^^^^^^ 💡 error: no such field |
130 | } | 127 | } |
131 | } | 128 | } |
132 | } | 129 | } |
diff --git a/crates/ide/src/diagnostics/remove_this_semicolon.rs b/crates/ide_diagnostics/src/handlers/remove_this_semicolon.rs index 814cb0f8c..4e639f214 100644 --- a/crates/ide/src/diagnostics/remove_this_semicolon.rs +++ b/crates/ide_diagnostics/src/handlers/remove_this_semicolon.rs | |||
@@ -3,15 +3,12 @@ use ide_db::source_change::SourceChange; | |||
3 | use syntax::{ast, AstNode}; | 3 | use syntax::{ast, AstNode}; |
4 | use text_edit::TextEdit; | 4 | use text_edit::TextEdit; |
5 | 5 | ||
6 | use crate::{ | 6 | use crate::{fix, Assist, Diagnostic, DiagnosticsContext}; |
7 | diagnostics::{fix, Diagnostic, DiagnosticsContext}, | ||
8 | Assist, | ||
9 | }; | ||
10 | 7 | ||
11 | // Diagnostic: remove-this-semicolon | 8 | // Diagnostic: remove-this-semicolon |
12 | // | 9 | // |
13 | // This diagnostic is triggered when there's an erroneous `;` at the end of the block. | 10 | // This diagnostic is triggered when there's an erroneous `;` at the end of the block. |
14 | pub(super) fn remove_this_semicolon( | 11 | pub(crate) fn remove_this_semicolon( |
15 | ctx: &DiagnosticsContext<'_>, | 12 | ctx: &DiagnosticsContext<'_>, |
16 | d: &hir::RemoveThisSemicolon, | 13 | d: &hir::RemoveThisSemicolon, |
17 | ) -> Diagnostic { | 14 | ) -> Diagnostic { |
@@ -45,14 +42,14 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::RemoveThisSemicolon) -> Option<V | |||
45 | 42 | ||
46 | #[cfg(test)] | 43 | #[cfg(test)] |
47 | mod tests { | 44 | mod tests { |
48 | use crate::diagnostics::tests::{check_diagnostics, check_fix}; | 45 | use crate::tests::{check_diagnostics, check_fix}; |
49 | 46 | ||
50 | #[test] | 47 | #[test] |
51 | fn missing_semicolon() { | 48 | fn missing_semicolon() { |
52 | check_diagnostics( | 49 | check_diagnostics( |
53 | r#" | 50 | r#" |
54 | fn test() -> i32 { 123; } | 51 | fn test() -> i32 { 123; } |
55 | //^^^ remove this semicolon | 52 | //^^^ 💡 error: remove this semicolon |
56 | "#, | 53 | "#, |
57 | ); | 54 | ); |
58 | } | 55 | } |
diff --git a/crates/ide/src/diagnostics/replace_filter_map_next_with_find_map.rs b/crates/ide_diagnostics/src/handlers/replace_filter_map_next_with_find_map.rs index f3b011495..cd87a10bb 100644 --- a/crates/ide/src/diagnostics/replace_filter_map_next_with_find_map.rs +++ b/crates/ide_diagnostics/src/handlers/replace_filter_map_next_with_find_map.rs | |||
@@ -6,15 +6,12 @@ use syntax::{ | |||
6 | }; | 6 | }; |
7 | use text_edit::TextEdit; | 7 | use text_edit::TextEdit; |
8 | 8 | ||
9 | use crate::{ | 9 | use crate::{fix, Assist, Diagnostic, DiagnosticsContext, Severity}; |
10 | diagnostics::{fix, Diagnostic, DiagnosticsContext}, | ||
11 | Assist, Severity, | ||
12 | }; | ||
13 | 10 | ||
14 | // Diagnostic: replace-filter-map-next-with-find-map | 11 | // Diagnostic: replace-filter-map-next-with-find-map |
15 | // | 12 | // |
16 | // This diagnostic is triggered when `.filter_map(..).next()` is used, rather than the more concise `.find_map(..)`. | 13 | // This diagnostic is triggered when `.filter_map(..).next()` is used, rather than the more concise `.find_map(..)`. |
17 | pub(super) fn replace_filter_map_next_with_find_map( | 14 | pub(crate) fn replace_filter_map_next_with_find_map( |
18 | ctx: &DiagnosticsContext<'_>, | 15 | ctx: &DiagnosticsContext<'_>, |
19 | d: &hir::ReplaceFilterMapNextWithFindMap, | 16 | d: &hir::ReplaceFilterMapNextWithFindMap, |
20 | ) -> Diagnostic { | 17 | ) -> Diagnostic { |
@@ -58,7 +55,7 @@ fn fixes( | |||
58 | 55 | ||
59 | #[cfg(test)] | 56 | #[cfg(test)] |
60 | mod tests { | 57 | mod tests { |
61 | use crate::diagnostics::tests::check_fix; | 58 | use crate::tests::check_fix; |
62 | 59 | ||
63 | // Register the required standard library types to make the tests work | 60 | // Register the required standard library types to make the tests work |
64 | #[track_caller] | 61 | #[track_caller] |
@@ -86,7 +83,7 @@ pub mod iter { | |||
86 | } | 83 | } |
87 | } | 84 | } |
88 | "#; | 85 | "#; |
89 | crate::diagnostics::tests::check_diagnostics(&format!("{}{}{}", prefix, ra_fixture, suffix)) | 86 | crate::tests::check_diagnostics(&format!("{}{}{}", prefix, ra_fixture, suffix)) |
90 | } | 87 | } |
91 | 88 | ||
92 | #[test] | 89 | #[test] |
@@ -94,8 +91,8 @@ pub mod iter { | |||
94 | check_diagnostics( | 91 | check_diagnostics( |
95 | r#" | 92 | r#" |
96 | fn foo() { | 93 | fn foo() { |
97 | let m = [1, 2, 3].iter().filter_map(|x| if *x == 2 { Some (4) } else { None }).next(); | 94 | let m = [1, 2, 3].iter().filter_map(|x| Some(92)).next(); |
98 | } //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ replace filter_map(..).next() with find_map(..) | 95 | } //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 💡 weak: replace filter_map(..).next() with find_map(..) |
99 | "#, | 96 | "#, |
100 | ); | 97 | ); |
101 | } | 98 | } |
@@ -107,7 +104,7 @@ pub mod iter { | |||
107 | fn foo() { | 104 | fn foo() { |
108 | let m = [1, 2, 3] | 105 | let m = [1, 2, 3] |
109 | .iter() | 106 | .iter() |
110 | .filter_map(|x| if *x == 2 { Some (4) } else { None }) | 107 | .filter_map(|x| Some(92)) |
111 | .len(); | 108 | .len(); |
112 | } | 109 | } |
113 | "#, | 110 | "#, |
@@ -121,7 +118,7 @@ fn foo() { | |||
121 | fn foo() { | 118 | fn foo() { |
122 | let m = [1, 2, 3] | 119 | let m = [1, 2, 3] |
123 | .iter() | 120 | .iter() |
124 | .filter_map(|x| if *x == 2 { Some (4) } else { None }) | 121 | .filter_map(|x| Some(92)) |
125 | .map(|x| x + 2) | 122 | .map(|x| x + 2) |
126 | .len(); | 123 | .len(); |
127 | } | 124 | } |
@@ -136,7 +133,7 @@ fn foo() { | |||
136 | fn foo() { | 133 | fn foo() { |
137 | let m = [1, 2, 3] | 134 | let m = [1, 2, 3] |
138 | .iter() | 135 | .iter() |
139 | .filter_map(|x| if *x == 2 { Some (4) } else { None }); | 136 | .filter_map(|x| Some(92)); |
140 | let n = m.next(); | 137 | let n = m.next(); |
141 | } | 138 | } |
142 | "#, | 139 | "#, |
@@ -151,7 +148,7 @@ fn foo() { | |||
151 | use core::iter::Iterator; | 148 | use core::iter::Iterator; |
152 | use core::option::Option::{self, Some, None}; | 149 | use core::option::Option::{self, Some, None}; |
153 | fn foo() { | 150 | fn foo() { |
154 | let m = [1, 2, 3].iter().$0filter_map(|x| if *x == 2 { Some (4) } else { None }).next(); | 151 | let m = [1, 2, 3].iter().$0filter_map(|x| Some(92)).next(); |
155 | } | 152 | } |
156 | //- /core/lib.rs crate:core | 153 | //- /core/lib.rs crate:core |
157 | pub mod option { | 154 | pub mod option { |
@@ -174,7 +171,7 @@ pub mod iter { | |||
174 | use core::iter::Iterator; | 171 | use core::iter::Iterator; |
175 | use core::option::Option::{self, Some, None}; | 172 | use core::option::Option::{self, Some, None}; |
176 | fn foo() { | 173 | fn foo() { |
177 | let m = [1, 2, 3].iter().find_map(|x| if *x == 2 { Some (4) } else { None }); | 174 | let m = [1, 2, 3].iter().find_map(|x| Some(92)); |
178 | } | 175 | } |
179 | "#, | 176 | "#, |
180 | ) | 177 | ) |
diff --git a/crates/ide/src/diagnostics/unimplemented_builtin_macro.rs b/crates/ide_diagnostics/src/handlers/unimplemented_builtin_macro.rs index 09faa3bbc..e879de75c 100644 --- a/crates/ide/src/diagnostics/unimplemented_builtin_macro.rs +++ b/crates/ide_diagnostics/src/handlers/unimplemented_builtin_macro.rs | |||
@@ -1,12 +1,9 @@ | |||
1 | use crate::{ | 1 | use crate::{Diagnostic, DiagnosticsContext, Severity}; |
2 | diagnostics::{Diagnostic, DiagnosticsContext}, | ||
3 | Severity, | ||
4 | }; | ||
5 | 2 | ||
6 | // Diagnostic: unimplemented-builtin-macro | 3 | // Diagnostic: unimplemented-builtin-macro |
7 | // | 4 | // |
8 | // This diagnostic is shown for builtin macros which are not yet implemented by rust-analyzer | 5 | // This diagnostic is shown for builtin macros which are not yet implemented by rust-analyzer |
9 | pub(super) fn unimplemented_builtin_macro( | 6 | pub(crate) fn unimplemented_builtin_macro( |
10 | ctx: &DiagnosticsContext<'_>, | 7 | ctx: &DiagnosticsContext<'_>, |
11 | d: &hir::UnimplementedBuiltinMacro, | 8 | d: &hir::UnimplementedBuiltinMacro, |
12 | ) -> Diagnostic { | 9 | ) -> Diagnostic { |
diff --git a/crates/ide/src/diagnostics/unlinked_file.rs b/crates/ide_diagnostics/src/handlers/unlinked_file.rs index a5b2e3399..8e601fa48 100644 --- a/crates/ide/src/diagnostics/unlinked_file.rs +++ b/crates/ide_diagnostics/src/handlers/unlinked_file.rs | |||
@@ -12,37 +12,31 @@ use syntax::{ | |||
12 | }; | 12 | }; |
13 | use text_edit::TextEdit; | 13 | use text_edit::TextEdit; |
14 | 14 | ||
15 | use crate::{ | 15 | use crate::{fix, Assist, Diagnostic, DiagnosticsContext}; |
16 | diagnostics::{fix, DiagnosticsContext}, | ||
17 | Assist, Diagnostic, | ||
18 | }; | ||
19 | |||
20 | #[derive(Debug)] | ||
21 | pub(crate) struct UnlinkedFile { | ||
22 | pub(crate) file: FileId, | ||
23 | } | ||
24 | 16 | ||
25 | // Diagnostic: unlinked-file | 17 | // Diagnostic: unlinked-file |
26 | // | 18 | // |
27 | // This diagnostic is shown for files that are not included in any crate, or files that are part of | 19 | // This diagnostic is shown for files that are not included in any crate, or files that are part of |
28 | // crates rust-analyzer failed to discover. The file will not have IDE features available. | 20 | // crates rust-analyzer failed to discover. The file will not have IDE features available. |
29 | pub(super) fn unlinked_file(ctx: &DiagnosticsContext, d: &UnlinkedFile) -> Diagnostic { | 21 | pub(crate) fn unlinked_file(ctx: &DiagnosticsContext, acc: &mut Vec<Diagnostic>, file_id: FileId) { |
30 | // Limit diagnostic to the first few characters in the file. This matches how VS Code | 22 | // Limit diagnostic to the first few characters in the file. This matches how VS Code |
31 | // renders it with the full span, but on other editors, and is less invasive. | 23 | // renders it with the full span, but on other editors, and is less invasive. |
32 | let range = ctx.sema.db.parse(d.file).syntax_node().text_range(); | 24 | let range = ctx.sema.db.parse(file_id).syntax_node().text_range(); |
33 | // FIXME: This is wrong if one of the first three characters is not ascii: `//Ы`. | 25 | // FIXME: This is wrong if one of the first three characters is not ascii: `//Ы`. |
34 | let range = range.intersect(TextRange::up_to(TextSize::of("..."))).unwrap_or(range); | 26 | let range = range.intersect(TextRange::up_to(TextSize::of("..."))).unwrap_or(range); |
35 | 27 | ||
36 | Diagnostic::new("unlinked-file", "file not included in module tree", range) | 28 | acc.push( |
37 | .with_fixes(fixes(ctx, d)) | 29 | Diagnostic::new("unlinked-file", "file not included in module tree", range) |
30 | .with_fixes(fixes(ctx, file_id)), | ||
31 | ); | ||
38 | } | 32 | } |
39 | 33 | ||
40 | fn fixes(ctx: &DiagnosticsContext, d: &UnlinkedFile) -> Option<Vec<Assist>> { | 34 | fn fixes(ctx: &DiagnosticsContext, file_id: FileId) -> Option<Vec<Assist>> { |
41 | // If there's an existing module that could add `mod` or `pub mod` items to include the unlinked file, | 35 | // If there's an existing module that could add `mod` or `pub mod` items to include the unlinked file, |
42 | // suggest that as a fix. | 36 | // suggest that as a fix. |
43 | 37 | ||
44 | let source_root = ctx.sema.db.source_root(ctx.sema.db.file_source_root(d.file)); | 38 | let source_root = ctx.sema.db.source_root(ctx.sema.db.file_source_root(file_id)); |
45 | let our_path = source_root.path_for_file(&d.file)?; | 39 | let our_path = source_root.path_for_file(&file_id)?; |
46 | let module_name = our_path.name_and_extension()?.0; | 40 | let module_name = our_path.name_and_extension()?.0; |
47 | 41 | ||
48 | // Candidates to look for: | 42 | // Candidates to look for: |
@@ -71,7 +65,7 @@ fn fixes(ctx: &DiagnosticsContext, d: &UnlinkedFile) -> Option<Vec<Assist>> { | |||
71 | } | 65 | } |
72 | 66 | ||
73 | if module.origin.file_id() == Some(*parent_id) { | 67 | if module.origin.file_id() == Some(*parent_id) { |
74 | return make_fixes(ctx.sema.db, *parent_id, module_name, d.file); | 68 | return make_fixes(ctx.sema.db, *parent_id, module_name, file_id); |
75 | } | 69 | } |
76 | } | 70 | } |
77 | } | 71 | } |
@@ -164,7 +158,7 @@ fn make_fixes( | |||
164 | 158 | ||
165 | #[cfg(test)] | 159 | #[cfg(test)] |
166 | mod tests { | 160 | mod tests { |
167 | use crate::diagnostics::tests::{check_diagnostics, check_fix, check_fixes, check_no_fix}; | 161 | use crate::tests::{check_diagnostics, check_fix, check_fixes, check_no_fix}; |
168 | 162 | ||
169 | #[test] | 163 | #[test] |
170 | fn unlinked_file_prepend_first_item() { | 164 | fn unlinked_file_prepend_first_item() { |
diff --git a/crates/ide/src/diagnostics/unresolved_extern_crate.rs b/crates/ide_diagnostics/src/handlers/unresolved_extern_crate.rs index 2ea79c2ee..74e4a69c6 100644 --- a/crates/ide/src/diagnostics/unresolved_extern_crate.rs +++ b/crates/ide_diagnostics/src/handlers/unresolved_extern_crate.rs | |||
@@ -1,9 +1,9 @@ | |||
1 | use crate::diagnostics::{Diagnostic, DiagnosticsContext}; | 1 | use crate::{Diagnostic, DiagnosticsContext}; |
2 | 2 | ||
3 | // Diagnostic: unresolved-extern-crate | 3 | // Diagnostic: unresolved-extern-crate |
4 | // | 4 | // |
5 | // This diagnostic is triggered if rust-analyzer is unable to discover referred extern crate. | 5 | // This diagnostic is triggered if rust-analyzer is unable to discover referred extern crate. |
6 | pub(super) fn unresolved_extern_crate( | 6 | pub(crate) fn unresolved_extern_crate( |
7 | ctx: &DiagnosticsContext<'_>, | 7 | ctx: &DiagnosticsContext<'_>, |
8 | d: &hir::UnresolvedExternCrate, | 8 | d: &hir::UnresolvedExternCrate, |
9 | ) -> Diagnostic { | 9 | ) -> Diagnostic { |
@@ -16,7 +16,7 @@ pub(super) fn unresolved_extern_crate( | |||
16 | 16 | ||
17 | #[cfg(test)] | 17 | #[cfg(test)] |
18 | mod tests { | 18 | mod tests { |
19 | use crate::diagnostics::tests::check_diagnostics; | 19 | use crate::tests::check_diagnostics; |
20 | 20 | ||
21 | #[test] | 21 | #[test] |
22 | fn unresolved_extern_crate() { | 22 | fn unresolved_extern_crate() { |
@@ -25,7 +25,7 @@ mod tests { | |||
25 | //- /main.rs crate:main deps:core | 25 | //- /main.rs crate:main deps:core |
26 | extern crate core; | 26 | extern crate core; |
27 | extern crate doesnotexist; | 27 | extern crate doesnotexist; |
28 | //^^^^^^^^^^^^^^^^^^^^^^^^^^ unresolved extern crate | 28 | //^^^^^^^^^^^^^^^^^^^^^^^^^^ error: unresolved extern crate |
29 | //- /lib.rs crate:core | 29 | //- /lib.rs crate:core |
30 | "#, | 30 | "#, |
31 | ); | 31 | ); |
@@ -38,7 +38,7 @@ extern crate core; | |||
38 | r#" | 38 | r#" |
39 | //- /lib.rs | 39 | //- /lib.rs |
40 | extern crate doesnotexist; | 40 | extern crate doesnotexist; |
41 | //^^^^^^^^^^^^^^^^^^^^^^^^^^ unresolved extern crate | 41 | //^^^^^^^^^^^^^^^^^^^^^^^^^^ error: unresolved extern crate |
42 | // Should not error. | 42 | // Should not error. |
43 | extern crate self as foo; | 43 | extern crate self as foo; |
44 | struct Foo; | 44 | struct Foo; |
diff --git a/crates/ide/src/diagnostics/unresolved_import.rs b/crates/ide_diagnostics/src/handlers/unresolved_import.rs index 1cbf96ba1..e52a88459 100644 --- a/crates/ide/src/diagnostics/unresolved_import.rs +++ b/crates/ide_diagnostics/src/handlers/unresolved_import.rs | |||
@@ -1,10 +1,10 @@ | |||
1 | use crate::diagnostics::{Diagnostic, DiagnosticsContext}; | 1 | use crate::{Diagnostic, DiagnosticsContext}; |
2 | 2 | ||
3 | // Diagnostic: unresolved-import | 3 | // Diagnostic: unresolved-import |
4 | // | 4 | // |
5 | // This diagnostic is triggered if rust-analyzer is unable to resolve a path in | 5 | // This diagnostic is triggered if rust-analyzer is unable to resolve a path in |
6 | // a `use` declaration. | 6 | // a `use` declaration. |
7 | pub(super) fn unresolved_import( | 7 | pub(crate) fn unresolved_import( |
8 | ctx: &DiagnosticsContext<'_>, | 8 | ctx: &DiagnosticsContext<'_>, |
9 | d: &hir::UnresolvedImport, | 9 | d: &hir::UnresolvedImport, |
10 | ) -> Diagnostic { | 10 | ) -> Diagnostic { |
@@ -22,7 +22,7 @@ pub(super) fn unresolved_import( | |||
22 | 22 | ||
23 | #[cfg(test)] | 23 | #[cfg(test)] |
24 | mod tests { | 24 | mod tests { |
25 | use crate::diagnostics::tests::check_diagnostics; | 25 | use crate::tests::check_diagnostics; |
26 | 26 | ||
27 | #[test] | 27 | #[test] |
28 | fn unresolved_import() { | 28 | fn unresolved_import() { |
@@ -30,7 +30,7 @@ mod tests { | |||
30 | r#" | 30 | r#" |
31 | use does_exist; | 31 | use does_exist; |
32 | use does_not_exist; | 32 | use does_not_exist; |
33 | //^^^^^^^^^^^^^^ unresolved import | 33 | //^^^^^^^^^^^^^^ error: unresolved import |
34 | 34 | ||
35 | mod does_exist {} | 35 | mod does_exist {} |
36 | "#, | 36 | "#, |
@@ -43,18 +43,18 @@ mod does_exist {} | |||
43 | check_diagnostics( | 43 | check_diagnostics( |
44 | r#" | 44 | r#" |
45 | use does_exist::{Exists, DoesntExist}; | 45 | use does_exist::{Exists, DoesntExist}; |
46 | //^^^^^^^^^^^ unresolved import | 46 | //^^^^^^^^^^^ error: unresolved import |
47 | 47 | ||
48 | use {does_not_exist::*, does_exist}; | 48 | use {does_not_exist::*, does_exist}; |
49 | //^^^^^^^^^^^^^^^^^ unresolved import | 49 | //^^^^^^^^^^^^^^^^^ error: unresolved import |
50 | 50 | ||
51 | use does_not_exist::{ | 51 | use does_not_exist::{ |
52 | a, | 52 | a, |
53 | //^ unresolved import | 53 | //^ error: unresolved import |
54 | b, | 54 | b, |
55 | //^ unresolved import | 55 | //^ error: unresolved import |
56 | c, | 56 | c, |
57 | //^ unresolved import | 57 | //^ error: unresolved import |
58 | }; | 58 | }; |
59 | 59 | ||
60 | mod does_exist { | 60 | mod does_exist { |
@@ -71,18 +71,18 @@ mod does_exist { | |||
71 | //- /main.rs crate:main | 71 | //- /main.rs crate:main |
72 | mod a { | 72 | mod a { |
73 | extern crate doesnotexist; | 73 | extern crate doesnotexist; |
74 | //^^^^^^^^^^^^^^^^^^^^^^^^^^ unresolved extern crate | 74 | //^^^^^^^^^^^^^^^^^^^^^^^^^^ error: unresolved extern crate |
75 | 75 | ||
76 | // Should not error, since we already errored for the missing crate. | 76 | // Should not error, since we already errored for the missing crate. |
77 | use doesnotexist::{self, bla, *}; | 77 | use doesnotexist::{self, bla, *}; |
78 | 78 | ||
79 | use crate::doesnotexist; | 79 | use crate::doesnotexist; |
80 | //^^^^^^^^^^^^^^^^^^^ unresolved import | 80 | //^^^^^^^^^^^^^^^^^^^ error: unresolved import |
81 | } | 81 | } |
82 | 82 | ||
83 | mod m { | 83 | mod m { |
84 | use super::doesnotexist; | 84 | use super::doesnotexist; |
85 | //^^^^^^^^^^^^^^^^^^^ unresolved import | 85 | //^^^^^^^^^^^^^^^^^^^ error: unresolved import |
86 | } | 86 | } |
87 | "#, | 87 | "#, |
88 | ); | 88 | ); |
diff --git a/crates/ide/src/diagnostics/unresolved_macro_call.rs b/crates/ide_diagnostics/src/handlers/unresolved_macro_call.rs index 15b6a2730..f0f7725db 100644 --- a/crates/ide/src/diagnostics/unresolved_macro_call.rs +++ b/crates/ide_diagnostics/src/handlers/unresolved_macro_call.rs | |||
@@ -1,13 +1,13 @@ | |||
1 | use hir::{db::AstDatabase, InFile}; | 1 | use hir::{db::AstDatabase, InFile}; |
2 | use syntax::{AstNode, SyntaxNodePtr}; | 2 | use syntax::{AstNode, SyntaxNodePtr}; |
3 | 3 | ||
4 | use crate::diagnostics::{Diagnostic, DiagnosticsContext}; | 4 | use crate::{Diagnostic, DiagnosticsContext}; |
5 | 5 | ||
6 | // Diagnostic: unresolved-macro-call | 6 | // Diagnostic: unresolved-macro-call |
7 | // | 7 | // |
8 | // This diagnostic is triggered if rust-analyzer is unable to resolve the path | 8 | // This diagnostic is triggered if rust-analyzer is unable to resolve the path |
9 | // to a macro in a macro invocation. | 9 | // to a macro in a macro invocation. |
10 | pub(super) fn unresolved_macro_call( | 10 | pub(crate) fn unresolved_macro_call( |
11 | ctx: &DiagnosticsContext<'_>, | 11 | ctx: &DiagnosticsContext<'_>, |
12 | d: &hir::UnresolvedMacroCall, | 12 | d: &hir::UnresolvedMacroCall, |
13 | ) -> Diagnostic { | 13 | ) -> Diagnostic { |
@@ -32,7 +32,7 @@ pub(super) fn unresolved_macro_call( | |||
32 | 32 | ||
33 | #[cfg(test)] | 33 | #[cfg(test)] |
34 | mod tests { | 34 | mod tests { |
35 | use crate::diagnostics::tests::check_diagnostics; | 35 | use crate::tests::check_diagnostics; |
36 | 36 | ||
37 | #[test] | 37 | #[test] |
38 | fn unresolved_macro_diag() { | 38 | fn unresolved_macro_diag() { |
@@ -40,7 +40,7 @@ mod tests { | |||
40 | r#" | 40 | r#" |
41 | fn f() { | 41 | fn f() { |
42 | m!(); | 42 | m!(); |
43 | } //^ unresolved macro `m!` | 43 | } //^ error: unresolved macro `m!` |
44 | 44 | ||
45 | "#, | 45 | "#, |
46 | ); | 46 | ); |
@@ -51,7 +51,7 @@ fn f() { | |||
51 | check_diagnostics( | 51 | check_diagnostics( |
52 | r#" | 52 | r#" |
53 | foo::bar!(92); | 53 | foo::bar!(92); |
54 | //^^^ unresolved macro `foo::bar!` | 54 | //^^^ error: unresolved macro `foo::bar!` |
55 | "#, | 55 | "#, |
56 | ); | 56 | ); |
57 | } | 57 | } |
@@ -63,7 +63,7 @@ foo::bar!(92); | |||
63 | macro_rules! m { () => {} } | 63 | macro_rules! m { () => {} } |
64 | 64 | ||
65 | m!(); m2!(); | 65 | m!(); m2!(); |
66 | //^^ unresolved macro `self::m2!` | 66 | //^^ error: unresolved macro `self::m2!` |
67 | "#, | 67 | "#, |
68 | ); | 68 | ); |
69 | } | 69 | } |
@@ -77,7 +77,7 @@ mod mac { | |||
77 | macro_rules! m { () => {} } } | 77 | macro_rules! m { () => {} } } |
78 | 78 | ||
79 | self::m!(); self::m2!(); | 79 | self::m!(); self::m2!(); |
80 | //^^ unresolved macro `self::m2!` | 80 | //^^ error: unresolved macro `self::m2!` |
81 | "#, | 81 | "#, |
82 | ); | 82 | ); |
83 | } | 83 | } |
diff --git a/crates/ide/src/diagnostics/unresolved_module.rs b/crates/ide_diagnostics/src/handlers/unresolved_module.rs index 977b46414..61fc43604 100644 --- a/crates/ide/src/diagnostics/unresolved_module.rs +++ b/crates/ide_diagnostics/src/handlers/unresolved_module.rs | |||
@@ -1,14 +1,13 @@ | |||
1 | use hir::db::AstDatabase; | 1 | use hir::db::AstDatabase; |
2 | use ide_assists::Assist; | 2 | use ide_db::{assists::Assist, base_db::AnchoredPathBuf, source_change::FileSystemEdit}; |
3 | use ide_db::{base_db::AnchoredPathBuf, source_change::FileSystemEdit}; | ||
4 | use syntax::AstNode; | 3 | use syntax::AstNode; |
5 | 4 | ||
6 | use crate::diagnostics::{fix, Diagnostic, DiagnosticsContext}; | 5 | use crate::{fix, Diagnostic, DiagnosticsContext}; |
7 | 6 | ||
8 | // Diagnostic: unresolved-module | 7 | // Diagnostic: unresolved-module |
9 | // | 8 | // |
10 | // This diagnostic is triggered if rust-analyzer is unable to discover referred module. | 9 | // This diagnostic is triggered if rust-analyzer is unable to discover referred module. |
11 | pub(super) fn unresolved_module( | 10 | pub(crate) fn unresolved_module( |
12 | ctx: &DiagnosticsContext<'_>, | 11 | ctx: &DiagnosticsContext<'_>, |
13 | d: &hir::UnresolvedModule, | 12 | d: &hir::UnresolvedModule, |
14 | ) -> Diagnostic { | 13 | ) -> Diagnostic { |
@@ -42,7 +41,7 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::UnresolvedModule) -> Option<Vec< | |||
42 | mod tests { | 41 | mod tests { |
43 | use expect_test::expect; | 42 | use expect_test::expect; |
44 | 43 | ||
45 | use crate::diagnostics::tests::{check_diagnostics, check_expect}; | 44 | use crate::tests::{check_diagnostics, check_expect}; |
46 | 45 | ||
47 | #[test] | 46 | #[test] |
48 | fn unresolved_module() { | 47 | fn unresolved_module() { |
@@ -51,7 +50,7 @@ mod tests { | |||
51 | //- /lib.rs | 50 | //- /lib.rs |
52 | mod foo; | 51 | mod foo; |
53 | mod bar; | 52 | mod bar; |
54 | //^^^^^^^^ unresolved module | 53 | //^^^^^^^^ 💡 error: unresolved module |
55 | mod baz {} | 54 | mod baz {} |
56 | //- /foo.rs | 55 | //- /foo.rs |
57 | "#, | 56 | "#, |
diff --git a/crates/ide/src/diagnostics/unresolved_proc_macro.rs b/crates/ide_diagnostics/src/handlers/unresolved_proc_macro.rs index 3dc6ab451..fde1d1323 100644 --- a/crates/ide/src/diagnostics/unresolved_proc_macro.rs +++ b/crates/ide_diagnostics/src/handlers/unresolved_proc_macro.rs | |||
@@ -1,7 +1,4 @@ | |||
1 | use crate::{ | 1 | use crate::{Diagnostic, DiagnosticsContext, Severity}; |
2 | diagnostics::{Diagnostic, DiagnosticsContext}, | ||
3 | Severity, | ||
4 | }; | ||
5 | 2 | ||
6 | // Diagnostic: unresolved-proc-macro | 3 | // Diagnostic: unresolved-proc-macro |
7 | // | 4 | // |
@@ -12,7 +9,7 @@ use crate::{ | |||
12 | // If you are seeing a lot of "proc macro not expanded" warnings, you can add this option to the | 9 | // If you are seeing a lot of "proc macro not expanded" warnings, you can add this option to the |
13 | // `rust-analyzer.diagnostics.disabled` list to prevent them from showing. Alternatively you can | 10 | // `rust-analyzer.diagnostics.disabled` list to prevent them from showing. Alternatively you can |
14 | // enable support for procedural macros (see `rust-analyzer.procMacro.enable`). | 11 | // enable support for procedural macros (see `rust-analyzer.procMacro.enable`). |
15 | pub(super) fn unresolved_proc_macro( | 12 | pub(crate) fn unresolved_proc_macro( |
16 | ctx: &DiagnosticsContext<'_>, | 13 | ctx: &DiagnosticsContext<'_>, |
17 | d: &hir::UnresolvedProcMacro, | 14 | d: &hir::UnresolvedProcMacro, |
18 | ) -> Diagnostic { | 15 | ) -> Diagnostic { |
diff --git a/crates/ide_diagnostics/src/handlers/useless_braces.rs b/crates/ide_diagnostics/src/handlers/useless_braces.rs new file mode 100644 index 000000000..8b9330e04 --- /dev/null +++ b/crates/ide_diagnostics/src/handlers/useless_braces.rs | |||
@@ -0,0 +1,148 @@ | |||
1 | use ide_db::{base_db::FileId, source_change::SourceChange}; | ||
2 | use itertools::Itertools; | ||
3 | use syntax::{ast, AstNode, SyntaxNode, TextRange}; | ||
4 | use text_edit::TextEdit; | ||
5 | |||
6 | use crate::{fix, Diagnostic, Severity}; | ||
7 | |||
8 | // Diagnostic: unnecessary-braces | ||
9 | // | ||
10 | // Diagnostic for unnecessary braces in `use` items. | ||
11 | pub(crate) fn useless_braces( | ||
12 | acc: &mut Vec<Diagnostic>, | ||
13 | file_id: FileId, | ||
14 | node: &SyntaxNode, | ||
15 | ) -> Option<()> { | ||
16 | let use_tree_list = ast::UseTreeList::cast(node.clone())?; | ||
17 | if let Some((single_use_tree,)) = use_tree_list.use_trees().collect_tuple() { | ||
18 | // If there is a comment inside the bracketed `use`, | ||
19 | // assume it is a commented out module path and don't show diagnostic. | ||
20 | if use_tree_list.has_inner_comment() { | ||
21 | return Some(()); | ||
22 | } | ||
23 | |||
24 | let use_range = use_tree_list.syntax().text_range(); | ||
25 | let edit = remove_braces(&single_use_tree).unwrap_or_else(|| { | ||
26 | let to_replace = single_use_tree.syntax().text().to_string(); | ||
27 | let mut edit_builder = TextEdit::builder(); | ||
28 | edit_builder.delete(use_range); | ||
29 | edit_builder.insert(use_range.start(), to_replace); | ||
30 | edit_builder.finish() | ||
31 | }); | ||
32 | |||
33 | acc.push( | ||
34 | Diagnostic::new( | ||
35 | "unnecessary-braces", | ||
36 | "Unnecessary braces in use statement".to_string(), | ||
37 | use_range, | ||
38 | ) | ||
39 | .severity(Severity::WeakWarning) | ||
40 | .with_fixes(Some(vec![fix( | ||
41 | "remove_braces", | ||
42 | "Remove unnecessary braces", | ||
43 | SourceChange::from_text_edit(file_id, edit), | ||
44 | use_range, | ||
45 | )])), | ||
46 | ); | ||
47 | } | ||
48 | |||
49 | Some(()) | ||
50 | } | ||
51 | |||
52 | fn remove_braces(single_use_tree: &ast::UseTree) -> Option<TextEdit> { | ||
53 | let use_tree_list_node = single_use_tree.syntax().parent()?; | ||
54 | if single_use_tree.path()?.segment()?.self_token().is_some() { | ||
55 | let start = use_tree_list_node.prev_sibling_or_token()?.text_range().start(); | ||
56 | let end = use_tree_list_node.text_range().end(); | ||
57 | return Some(TextEdit::delete(TextRange::new(start, end))); | ||
58 | } | ||
59 | None | ||
60 | } | ||
61 | |||
62 | #[cfg(test)] | ||
63 | mod tests { | ||
64 | use crate::tests::{check_diagnostics, check_fix}; | ||
65 | |||
66 | #[test] | ||
67 | fn test_check_unnecessary_braces_in_use_statement() { | ||
68 | check_diagnostics( | ||
69 | r#" | ||
70 | use a; | ||
71 | use a::{c, d::e}; | ||
72 | |||
73 | mod a { | ||
74 | mod c {} | ||
75 | mod d { | ||
76 | mod e {} | ||
77 | } | ||
78 | } | ||
79 | "#, | ||
80 | ); | ||
81 | check_diagnostics( | ||
82 | r#" | ||
83 | use a; | ||
84 | use a::{ | ||
85 | c, | ||
86 | // d::e | ||
87 | }; | ||
88 | |||
89 | mod a { | ||
90 | mod c {} | ||
91 | mod d { | ||
92 | mod e {} | ||
93 | } | ||
94 | } | ||
95 | "#, | ||
96 | ); | ||
97 | check_fix( | ||
98 | r#" | ||
99 | mod b {} | ||
100 | use {$0b}; | ||
101 | "#, | ||
102 | r#" | ||
103 | mod b {} | ||
104 | use b; | ||
105 | "#, | ||
106 | ); | ||
107 | check_fix( | ||
108 | r#" | ||
109 | mod b {} | ||
110 | use {b$0}; | ||
111 | "#, | ||
112 | r#" | ||
113 | mod b {} | ||
114 | use b; | ||
115 | "#, | ||
116 | ); | ||
117 | check_fix( | ||
118 | r#" | ||
119 | mod a { mod c {} } | ||
120 | use a::{c$0}; | ||
121 | "#, | ||
122 | r#" | ||
123 | mod a { mod c {} } | ||
124 | use a::c; | ||
125 | "#, | ||
126 | ); | ||
127 | check_fix( | ||
128 | r#" | ||
129 | mod a {} | ||
130 | use a::{self$0}; | ||
131 | "#, | ||
132 | r#" | ||
133 | mod a {} | ||
134 | use a; | ||
135 | "#, | ||
136 | ); | ||
137 | check_fix( | ||
138 | r#" | ||
139 | mod a { mod c {} mod d { mod e {} } } | ||
140 | use a::{c, d::{e$0}}; | ||
141 | "#, | ||
142 | r#" | ||
143 | mod a { mod c {} mod d { mod e {} } } | ||
144 | use a::{c, d::e}; | ||
145 | "#, | ||
146 | ); | ||
147 | } | ||
148 | } | ||
diff --git a/crates/ide_diagnostics/src/lib.rs b/crates/ide_diagnostics/src/lib.rs new file mode 100644 index 000000000..6ad1b4373 --- /dev/null +++ b/crates/ide_diagnostics/src/lib.rs | |||
@@ -0,0 +1,374 @@ | |||
1 | //! Diagnostics rendering and fixits. | ||
2 | //! | ||
3 | //! Most of the diagnostics originate from the dark depth of the compiler, and | ||
4 | //! are originally expressed in term of IR. When we emit the diagnostic, we are | ||
5 | //! usually not in the position to decide how to best "render" it in terms of | ||
6 | //! user-authored source code. We are especially not in the position to offer | ||
7 | //! fixits, as the compiler completely lacks the infrastructure to edit the | ||
8 | //! source code. | ||
9 | //! | ||
10 | //! Instead, we "bubble up" raw, structured diagnostics until the `hir` crate, | ||
11 | //! where we "cook" them so that each diagnostic is formulated in terms of `hir` | ||
12 | //! types. Well, at least that's the aspiration, the "cooking" is somewhat | ||
13 | //! ad-hoc at the moment. Anyways, we get a bunch of ide-friendly diagnostic | ||
14 | //! structs from hir, and we want to render them to unified serializable | ||
15 | //! representation (span, level, message) here. If we can, we also provide | ||
16 | //! fixits. By the way, that's why we want to keep diagnostics structured | ||
17 | //! internally -- so that we have all the info to make fixes. | ||
18 | //! | ||
19 | //! We have one "handler" module per diagnostic code. Such a module contains | ||
20 | //! rendering, optional fixes and tests. It's OK if some low-level compiler | ||
21 | //! functionality ends up being tested via a diagnostic. | ||
22 | //! | ||
23 | //! There are also a couple of ad-hoc diagnostics implemented directly here, we | ||
24 | //! don't yet have a great pattern for how to do them properly. | ||
25 | |||
26 | mod handlers { | ||
27 | pub(crate) mod break_outside_of_loop; | ||
28 | pub(crate) mod inactive_code; | ||
29 | pub(crate) mod incorrect_case; | ||
30 | pub(crate) mod macro_error; | ||
31 | pub(crate) mod mismatched_arg_count; | ||
32 | pub(crate) mod missing_fields; | ||
33 | pub(crate) mod missing_match_arms; | ||
34 | pub(crate) mod missing_ok_or_some_in_tail_expr; | ||
35 | pub(crate) mod missing_unsafe; | ||
36 | pub(crate) mod no_such_field; | ||
37 | pub(crate) mod remove_this_semicolon; | ||
38 | pub(crate) mod replace_filter_map_next_with_find_map; | ||
39 | pub(crate) mod unimplemented_builtin_macro; | ||
40 | pub(crate) mod unresolved_extern_crate; | ||
41 | pub(crate) mod unresolved_import; | ||
42 | pub(crate) mod unresolved_macro_call; | ||
43 | pub(crate) mod unresolved_module; | ||
44 | pub(crate) mod unresolved_proc_macro; | ||
45 | |||
46 | // The handlers bellow are unusual, the implement the diagnostics as well. | ||
47 | pub(crate) mod field_shorthand; | ||
48 | pub(crate) mod useless_braces; | ||
49 | pub(crate) mod unlinked_file; | ||
50 | } | ||
51 | |||
52 | use hir::{diagnostics::AnyDiagnostic, Semantics}; | ||
53 | use ide_db::{ | ||
54 | assists::{Assist, AssistId, AssistKind, AssistResolveStrategy}, | ||
55 | base_db::{FileId, SourceDatabase}, | ||
56 | label::Label, | ||
57 | source_change::SourceChange, | ||
58 | RootDatabase, | ||
59 | }; | ||
60 | use rustc_hash::FxHashSet; | ||
61 | use syntax::{ast::AstNode, TextRange}; | ||
62 | |||
63 | #[derive(Copy, Clone, Debug, PartialEq)] | ||
64 | pub struct DiagnosticCode(pub &'static str); | ||
65 | |||
66 | impl DiagnosticCode { | ||
67 | pub fn as_str(&self) -> &str { | ||
68 | self.0 | ||
69 | } | ||
70 | } | ||
71 | |||
72 | #[derive(Debug)] | ||
73 | pub struct Diagnostic { | ||
74 | pub code: DiagnosticCode, | ||
75 | pub message: String, | ||
76 | pub range: TextRange, | ||
77 | pub severity: Severity, | ||
78 | pub unused: bool, | ||
79 | pub experimental: bool, | ||
80 | pub fixes: Option<Vec<Assist>>, | ||
81 | } | ||
82 | |||
83 | impl Diagnostic { | ||
84 | fn new(code: &'static str, message: impl Into<String>, range: TextRange) -> Diagnostic { | ||
85 | let message = message.into(); | ||
86 | Diagnostic { | ||
87 | code: DiagnosticCode(code), | ||
88 | message, | ||
89 | range, | ||
90 | severity: Severity::Error, | ||
91 | unused: false, | ||
92 | experimental: false, | ||
93 | fixes: None, | ||
94 | } | ||
95 | } | ||
96 | |||
97 | fn experimental(mut self) -> Diagnostic { | ||
98 | self.experimental = true; | ||
99 | self | ||
100 | } | ||
101 | |||
102 | fn severity(mut self, severity: Severity) -> Diagnostic { | ||
103 | self.severity = severity; | ||
104 | self | ||
105 | } | ||
106 | |||
107 | fn with_fixes(mut self, fixes: Option<Vec<Assist>>) -> Diagnostic { | ||
108 | self.fixes = fixes; | ||
109 | self | ||
110 | } | ||
111 | |||
112 | fn with_unused(mut self, unused: bool) -> Diagnostic { | ||
113 | self.unused = unused; | ||
114 | self | ||
115 | } | ||
116 | } | ||
117 | |||
118 | #[derive(Debug, Copy, Clone)] | ||
119 | pub enum Severity { | ||
120 | Error, | ||
121 | // We don't actually emit this one yet, but we should at some point. | ||
122 | // Warning, | ||
123 | WeakWarning, | ||
124 | } | ||
125 | |||
126 | #[derive(Default, Debug, Clone)] | ||
127 | pub struct DiagnosticsConfig { | ||
128 | pub disable_experimental: bool, | ||
129 | pub disabled: FxHashSet<String>, | ||
130 | } | ||
131 | |||
132 | struct DiagnosticsContext<'a> { | ||
133 | config: &'a DiagnosticsConfig, | ||
134 | sema: Semantics<'a, RootDatabase>, | ||
135 | resolve: &'a AssistResolveStrategy, | ||
136 | } | ||
137 | |||
138 | pub fn diagnostics( | ||
139 | db: &RootDatabase, | ||
140 | config: &DiagnosticsConfig, | ||
141 | resolve: &AssistResolveStrategy, | ||
142 | file_id: FileId, | ||
143 | ) -> Vec<Diagnostic> { | ||
144 | let _p = profile::span("diagnostics"); | ||
145 | let sema = Semantics::new(db); | ||
146 | let parse = db.parse(file_id); | ||
147 | let mut res = Vec::new(); | ||
148 | |||
149 | // [#34344] Only take first 128 errors to prevent slowing down editor/ide, the number 128 is chosen arbitrarily. | ||
150 | res.extend( | ||
151 | parse.errors().iter().take(128).map(|err| { | ||
152 | Diagnostic::new("syntax-error", format!("Syntax Error: {}", err), err.range()) | ||
153 | }), | ||
154 | ); | ||
155 | |||
156 | for node in parse.tree().syntax().descendants() { | ||
157 | handlers::useless_braces::useless_braces(&mut res, file_id, &node); | ||
158 | handlers::field_shorthand::field_shorthand(&mut res, file_id, &node); | ||
159 | } | ||
160 | |||
161 | let module = sema.to_module_def(file_id); | ||
162 | |||
163 | let ctx = DiagnosticsContext { config, sema, resolve }; | ||
164 | if module.is_none() { | ||
165 | handlers::unlinked_file::unlinked_file(&ctx, &mut res, file_id); | ||
166 | } | ||
167 | |||
168 | let mut diags = Vec::new(); | ||
169 | if let Some(m) = module { | ||
170 | m.diagnostics(db, &mut diags) | ||
171 | } | ||
172 | |||
173 | for diag in diags { | ||
174 | #[rustfmt::skip] | ||
175 | let d = match diag { | ||
176 | AnyDiagnostic::BreakOutsideOfLoop(d) => handlers::break_outside_of_loop::break_outside_of_loop(&ctx, &d), | ||
177 | AnyDiagnostic::IncorrectCase(d) => handlers::incorrect_case::incorrect_case(&ctx, &d), | ||
178 | AnyDiagnostic::MacroError(d) => handlers::macro_error::macro_error(&ctx, &d), | ||
179 | AnyDiagnostic::MismatchedArgCount(d) => handlers::mismatched_arg_count::mismatched_arg_count(&ctx, &d), | ||
180 | AnyDiagnostic::MissingFields(d) => handlers::missing_fields::missing_fields(&ctx, &d), | ||
181 | AnyDiagnostic::MissingMatchArms(d) => handlers::missing_match_arms::missing_match_arms(&ctx, &d), | ||
182 | AnyDiagnostic::MissingOkOrSomeInTailExpr(d) => handlers::missing_ok_or_some_in_tail_expr::missing_ok_or_some_in_tail_expr(&ctx, &d), | ||
183 | AnyDiagnostic::MissingUnsafe(d) => handlers::missing_unsafe::missing_unsafe(&ctx, &d), | ||
184 | AnyDiagnostic::NoSuchField(d) => handlers::no_such_field::no_such_field(&ctx, &d), | ||
185 | AnyDiagnostic::RemoveThisSemicolon(d) => handlers::remove_this_semicolon::remove_this_semicolon(&ctx, &d), | ||
186 | AnyDiagnostic::ReplaceFilterMapNextWithFindMap(d) => handlers::replace_filter_map_next_with_find_map::replace_filter_map_next_with_find_map(&ctx, &d), | ||
187 | AnyDiagnostic::UnimplementedBuiltinMacro(d) => handlers::unimplemented_builtin_macro::unimplemented_builtin_macro(&ctx, &d), | ||
188 | AnyDiagnostic::UnresolvedExternCrate(d) => handlers::unresolved_extern_crate::unresolved_extern_crate(&ctx, &d), | ||
189 | AnyDiagnostic::UnresolvedImport(d) => handlers::unresolved_import::unresolved_import(&ctx, &d), | ||
190 | AnyDiagnostic::UnresolvedMacroCall(d) => handlers::unresolved_macro_call::unresolved_macro_call(&ctx, &d), | ||
191 | AnyDiagnostic::UnresolvedModule(d) => handlers::unresolved_module::unresolved_module(&ctx, &d), | ||
192 | AnyDiagnostic::UnresolvedProcMacro(d) => handlers::unresolved_proc_macro::unresolved_proc_macro(&ctx, &d), | ||
193 | |||
194 | AnyDiagnostic::InactiveCode(d) => match handlers::inactive_code::inactive_code(&ctx, &d) { | ||
195 | Some(it) => it, | ||
196 | None => continue, | ||
197 | } | ||
198 | }; | ||
199 | res.push(d) | ||
200 | } | ||
201 | |||
202 | res.retain(|d| { | ||
203 | !ctx.config.disabled.contains(d.code.as_str()) | ||
204 | && !(ctx.config.disable_experimental && d.experimental) | ||
205 | }); | ||
206 | |||
207 | res | ||
208 | } | ||
209 | |||
210 | fn fix(id: &'static str, label: &str, source_change: SourceChange, target: TextRange) -> Assist { | ||
211 | let mut res = unresolved_fix(id, label, target); | ||
212 | res.source_change = Some(source_change); | ||
213 | res | ||
214 | } | ||
215 | |||
216 | fn unresolved_fix(id: &'static str, label: &str, target: TextRange) -> Assist { | ||
217 | assert!(!id.contains(' ')); | ||
218 | Assist { | ||
219 | id: AssistId(id, AssistKind::QuickFix), | ||
220 | label: Label::new(label), | ||
221 | group: None, | ||
222 | target, | ||
223 | source_change: None, | ||
224 | } | ||
225 | } | ||
226 | |||
227 | #[cfg(test)] | ||
228 | mod tests { | ||
229 | use expect_test::Expect; | ||
230 | use ide_db::{ | ||
231 | assists::AssistResolveStrategy, | ||
232 | base_db::{fixture::WithFixture, SourceDatabaseExt}, | ||
233 | RootDatabase, | ||
234 | }; | ||
235 | use stdx::trim_indent; | ||
236 | use test_utils::{assert_eq_text, extract_annotations}; | ||
237 | |||
238 | use crate::{DiagnosticsConfig, Severity}; | ||
239 | |||
240 | /// Takes a multi-file input fixture with annotated cursor positions, | ||
241 | /// and checks that: | ||
242 | /// * a diagnostic is produced | ||
243 | /// * the first diagnostic fix trigger range touches the input cursor position | ||
244 | /// * that the contents of the file containing the cursor match `after` after the diagnostic fix is applied | ||
245 | #[track_caller] | ||
246 | pub(crate) fn check_fix(ra_fixture_before: &str, ra_fixture_after: &str) { | ||
247 | check_nth_fix(0, ra_fixture_before, ra_fixture_after); | ||
248 | } | ||
249 | /// Takes a multi-file input fixture with annotated cursor positions, | ||
250 | /// and checks that: | ||
251 | /// * a diagnostic is produced | ||
252 | /// * every diagnostic fixes trigger range touches the input cursor position | ||
253 | /// * that the contents of the file containing the cursor match `after` after each diagnostic fix is applied | ||
254 | pub(crate) fn check_fixes(ra_fixture_before: &str, ra_fixtures_after: Vec<&str>) { | ||
255 | for (i, ra_fixture_after) in ra_fixtures_after.iter().enumerate() { | ||
256 | check_nth_fix(i, ra_fixture_before, ra_fixture_after) | ||
257 | } | ||
258 | } | ||
259 | |||
260 | #[track_caller] | ||
261 | fn check_nth_fix(nth: usize, ra_fixture_before: &str, ra_fixture_after: &str) { | ||
262 | let after = trim_indent(ra_fixture_after); | ||
263 | |||
264 | let (db, file_position) = RootDatabase::with_position(ra_fixture_before); | ||
265 | let diagnostic = super::diagnostics( | ||
266 | &db, | ||
267 | &DiagnosticsConfig::default(), | ||
268 | &AssistResolveStrategy::All, | ||
269 | file_position.file_id, | ||
270 | ) | ||
271 | .pop() | ||
272 | .expect("no diagnostics"); | ||
273 | let fix = &diagnostic.fixes.expect("diagnostic misses fixes")[nth]; | ||
274 | let actual = { | ||
275 | let source_change = fix.source_change.as_ref().unwrap(); | ||
276 | let file_id = *source_change.source_file_edits.keys().next().unwrap(); | ||
277 | let mut actual = db.file_text(file_id).to_string(); | ||
278 | |||
279 | for edit in source_change.source_file_edits.values() { | ||
280 | edit.apply(&mut actual); | ||
281 | } | ||
282 | actual | ||
283 | }; | ||
284 | |||
285 | assert_eq_text!(&after, &actual); | ||
286 | assert!( | ||
287 | fix.target.contains_inclusive(file_position.offset), | ||
288 | "diagnostic fix range {:?} does not touch cursor position {:?}", | ||
289 | fix.target, | ||
290 | file_position.offset | ||
291 | ); | ||
292 | } | ||
293 | |||
294 | /// Checks that there's a diagnostic *without* fix at `$0`. | ||
295 | pub(crate) fn check_no_fix(ra_fixture: &str) { | ||
296 | let (db, file_position) = RootDatabase::with_position(ra_fixture); | ||
297 | let diagnostic = super::diagnostics( | ||
298 | &db, | ||
299 | &DiagnosticsConfig::default(), | ||
300 | &AssistResolveStrategy::All, | ||
301 | file_position.file_id, | ||
302 | ) | ||
303 | .pop() | ||
304 | .unwrap(); | ||
305 | assert!(diagnostic.fixes.is_none(), "got a fix when none was expected: {:?}", diagnostic); | ||
306 | } | ||
307 | |||
308 | pub(crate) fn check_expect(ra_fixture: &str, expect: Expect) { | ||
309 | let (db, file_id) = RootDatabase::with_single_file(ra_fixture); | ||
310 | let diagnostics = super::diagnostics( | ||
311 | &db, | ||
312 | &DiagnosticsConfig::default(), | ||
313 | &AssistResolveStrategy::All, | ||
314 | file_id, | ||
315 | ); | ||
316 | expect.assert_debug_eq(&diagnostics) | ||
317 | } | ||
318 | |||
319 | #[track_caller] | ||
320 | pub(crate) fn check_diagnostics(ra_fixture: &str) { | ||
321 | let mut config = DiagnosticsConfig::default(); | ||
322 | config.disabled.insert("inactive-code".to_string()); | ||
323 | check_diagnostics_with_config(config, ra_fixture) | ||
324 | } | ||
325 | |||
326 | #[track_caller] | ||
327 | pub(crate) fn check_diagnostics_with_config(config: DiagnosticsConfig, ra_fixture: &str) { | ||
328 | let (db, files) = RootDatabase::with_many_files(ra_fixture); | ||
329 | for file_id in files { | ||
330 | let diagnostics = | ||
331 | super::diagnostics(&db, &config, &AssistResolveStrategy::All, file_id); | ||
332 | |||
333 | let expected = extract_annotations(&*db.file_text(file_id)); | ||
334 | let mut actual = diagnostics | ||
335 | .into_iter() | ||
336 | .map(|d| { | ||
337 | let mut annotation = String::new(); | ||
338 | if let Some(fixes) = &d.fixes { | ||
339 | assert!(!fixes.is_empty()); | ||
340 | annotation.push_str("💡 ") | ||
341 | } | ||
342 | annotation.push_str(match d.severity { | ||
343 | Severity::Error => "error", | ||
344 | Severity::WeakWarning => "weak", | ||
345 | }); | ||
346 | annotation.push_str(": "); | ||
347 | annotation.push_str(&d.message); | ||
348 | (d.range, annotation) | ||
349 | }) | ||
350 | .collect::<Vec<_>>(); | ||
351 | actual.sort_by_key(|(range, _)| range.start()); | ||
352 | assert_eq!(expected, actual); | ||
353 | } | ||
354 | } | ||
355 | |||
356 | #[test] | ||
357 | fn test_disabled_diagnostics() { | ||
358 | let mut config = DiagnosticsConfig::default(); | ||
359 | config.disabled.insert("unresolved-module".into()); | ||
360 | |||
361 | let (db, file_id) = RootDatabase::with_single_file(r#"mod foo;"#); | ||
362 | |||
363 | let diagnostics = super::diagnostics(&db, &config, &AssistResolveStrategy::All, file_id); | ||
364 | assert!(diagnostics.is_empty()); | ||
365 | |||
366 | let diagnostics = super::diagnostics( | ||
367 | &db, | ||
368 | &DiagnosticsConfig::default(), | ||
369 | &AssistResolveStrategy::All, | ||
370 | file_id, | ||
371 | ); | ||
372 | assert!(!diagnostics.is_empty()); | ||
373 | } | ||
374 | } | ||
diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index 3b20d741a..5588c15da 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs | |||
@@ -1062,8 +1062,8 @@ mod tests { | |||
1062 | let package_json_path = project_root().join("editors/code/package.json"); | 1062 | let package_json_path = project_root().join("editors/code/package.json"); |
1063 | let mut package_json = fs::read_to_string(&package_json_path).unwrap(); | 1063 | let mut package_json = fs::read_to_string(&package_json_path).unwrap(); |
1064 | 1064 | ||
1065 | let start_marker = " \"$generated-start\": false,\n"; | 1065 | let start_marker = " \"$generated-start\": {},\n"; |
1066 | let end_marker = " \"$generated-end\": false\n"; | 1066 | let end_marker = " \"$generated-end\": {}\n"; |
1067 | 1067 | ||
1068 | let start = package_json.find(start_marker).unwrap() + start_marker.len(); | 1068 | let start = package_json.find(start_marker).unwrap() + start_marker.len(); |
1069 | let end = package_json.find(end_marker).unwrap(); | 1069 | let end = package_json.find(end_marker).unwrap(); |
diff --git a/crates/rust-analyzer/tests/slow-tests/support.rs b/crates/rust-analyzer/tests/slow-tests/support.rs index e22c295f9..260a504e7 100644 --- a/crates/rust-analyzer/tests/slow-tests/support.rs +++ b/crates/rust-analyzer/tests/slow-tests/support.rs | |||
@@ -75,7 +75,9 @@ impl<'a> Project<'a> { | |||
75 | profile::init_from(crate::PROFILE); | 75 | profile::init_from(crate::PROFILE); |
76 | }); | 76 | }); |
77 | 77 | ||
78 | for entry in Fixture::parse(self.fixture) { | 78 | let (mini_core, fixtures) = Fixture::parse(self.fixture); |
79 | assert!(mini_core.is_none()); | ||
80 | for entry in fixtures { | ||
79 | let path = tmp_dir.path().join(&entry.path['/'.len_utf8()..]); | 81 | let path = tmp_dir.path().join(&entry.path['/'.len_utf8()..]); |
80 | fs::create_dir_all(path.parent().unwrap()).unwrap(); | 82 | fs::create_dir_all(path.parent().unwrap()).unwrap(); |
81 | fs::write(path.as_path(), entry.text.as_bytes()).unwrap(); | 83 | fs::write(path.as_path(), entry.text.as_bytes()).unwrap(); |
diff --git a/crates/syntax/src/ast/node_ext.rs b/crates/syntax/src/ast/node_ext.rs index 3d27d2c1a..2bd9ad867 100644 --- a/crates/syntax/src/ast/node_ext.rs +++ b/crates/syntax/src/ast/node_ext.rs | |||
@@ -325,6 +325,15 @@ impl ast::Impl { | |||
325 | let second = types.next(); | 325 | let second = types.next(); |
326 | (first, second) | 326 | (first, second) |
327 | } | 327 | } |
328 | |||
329 | pub fn for_trait_name_ref(name_ref: &ast::NameRef) -> Option<ast::Impl> { | ||
330 | let this = name_ref.syntax().ancestors().find_map(ast::Impl::cast)?; | ||
331 | if this.trait_()?.syntax().text_range().start() == name_ref.syntax().text_range().start() { | ||
332 | Some(this) | ||
333 | } else { | ||
334 | None | ||
335 | } | ||
336 | } | ||
328 | } | 337 | } |
329 | 338 | ||
330 | #[derive(Debug, Clone, PartialEq, Eq)] | 339 | #[derive(Debug, Clone, PartialEq, Eq)] |
diff --git a/crates/syntax/test_data/parser/ok/0011_outer_attribute.rast b/crates/syntax/test_data/parser/ok/0011_outer_attribute.rast index ff5877a7b..31f76589d 100644 --- a/crates/syntax/test_data/parser/ok/0011_outer_attribute.rast +++ b/crates/syntax/test_data/parser/ok/0011_outer_attribute.rast | |||
@@ -21,7 +21,7 @@ [email protected] | |||
21 | [email protected] | 21 | [email protected] |
22 | [email protected] | 22 | [email protected] |
23 | [email protected] | 23 | [email protected] |
24 | [email protected] "ignore" | 24 | [email protected] "Ignore" |
25 | [email protected] "]" | 25 | [email protected] "]" |
26 | [email protected] "\n" | 26 | [email protected] "\n" |
27 | [email protected] "fn" | 27 | [email protected] "fn" |
diff --git a/crates/syntax/test_data/parser/ok/0011_outer_attribute.rs b/crates/syntax/test_data/parser/ok/0011_outer_attribute.rs index 3d2e01d5c..6f04cb171 100644 --- a/crates/syntax/test_data/parser/ok/0011_outer_attribute.rs +++ b/crates/syntax/test_data/parser/ok/0011_outer_attribute.rs | |||
@@ -1,5 +1,5 @@ | |||
1 | #[cfg(test)] | 1 | #[cfg(test)] |
2 | #[ignore] | 2 | #[Ignore] |
3 | fn foo() {} | 3 | fn foo() {} |
4 | 4 | ||
5 | #[path = "a.rs"] | 5 | #[path = "a.rs"] |
diff --git a/crates/test_utils/src/fixture.rs b/crates/test_utils/src/fixture.rs index d0bddf7d8..6ba112de8 100644 --- a/crates/test_utils/src/fixture.rs +++ b/crates/test_utils/src/fixture.rs | |||
@@ -77,6 +77,11 @@ pub struct Fixture { | |||
77 | pub introduce_new_source_root: bool, | 77 | pub introduce_new_source_root: bool, |
78 | } | 78 | } |
79 | 79 | ||
80 | pub struct MiniCore { | ||
81 | activated_flags: Vec<String>, | ||
82 | valid_flags: Vec<String>, | ||
83 | } | ||
84 | |||
80 | impl Fixture { | 85 | impl Fixture { |
81 | /// Parses text which looks like this: | 86 | /// Parses text which looks like this: |
82 | /// | 87 | /// |
@@ -86,12 +91,28 @@ impl Fixture { | |||
86 | /// line 2 | 91 | /// line 2 |
87 | /// //- other meta | 92 | /// //- other meta |
88 | /// ``` | 93 | /// ``` |
89 | pub fn parse(ra_fixture: &str) -> Vec<Fixture> { | 94 | /// |
95 | /// Fixture can also start with a minicore declaration: | ||
96 | /// | ||
97 | /// ``` | ||
98 | /// //- minicore: sized | ||
99 | /// ``` | ||
100 | /// | ||
101 | /// That will include a subset of `libcore` into the fixture, see | ||
102 | /// `minicore.rs` for what's available. | ||
103 | pub fn parse(ra_fixture: &str) -> (Option<MiniCore>, Vec<Fixture>) { | ||
90 | let fixture = trim_indent(ra_fixture); | 104 | let fixture = trim_indent(ra_fixture); |
91 | 105 | let mut fixture = fixture.as_str(); | |
106 | let mut mini_core = None; | ||
92 | let mut res: Vec<Fixture> = Vec::new(); | 107 | let mut res: Vec<Fixture> = Vec::new(); |
93 | 108 | ||
94 | let default = if ra_fixture.contains("//-") { None } else { Some("//- /main.rs") }; | 109 | if fixture.starts_with("//- minicore:") { |
110 | let first_line = fixture.split_inclusive('\n').next().unwrap(); | ||
111 | mini_core = Some(MiniCore::parse(first_line)); | ||
112 | fixture = &fixture[first_line.len()..]; | ||
113 | } | ||
114 | |||
115 | let default = if fixture.contains("//-") { None } else { Some("//- /main.rs") }; | ||
95 | 116 | ||
96 | for (ix, line) in default.into_iter().chain(fixture.split_inclusive('\n')).enumerate() { | 117 | for (ix, line) in default.into_iter().chain(fixture.split_inclusive('\n')).enumerate() { |
97 | if line.contains("//-") { | 118 | if line.contains("//-") { |
@@ -113,7 +134,7 @@ impl Fixture { | |||
113 | } | 134 | } |
114 | } | 135 | } |
115 | 136 | ||
116 | res | 137 | (mini_core, res) |
117 | } | 138 | } |
118 | 139 | ||
119 | //- /lib.rs crate:foo deps:bar,baz cfg:foo=a,bar=b env:OUTDIR=path/to,OTHER=foo | 140 | //- /lib.rs crate:foo deps:bar,baz cfg:foo=a,bar=b env:OUTDIR=path/to,OTHER=foo |
@@ -172,6 +193,133 @@ impl Fixture { | |||
172 | } | 193 | } |
173 | } | 194 | } |
174 | 195 | ||
196 | impl MiniCore { | ||
197 | fn has_flag(&self, flag: &str) -> bool { | ||
198 | self.activated_flags.iter().any(|it| it == flag) | ||
199 | } | ||
200 | |||
201 | #[track_caller] | ||
202 | fn assert_valid_flag(&self, flag: &str) { | ||
203 | if !self.valid_flags.iter().any(|it| it == flag) { | ||
204 | panic!("invalid flag: {:?}, valid flags: {:?}", flag, self.valid_flags); | ||
205 | } | ||
206 | } | ||
207 | |||
208 | fn parse(line: &str) -> MiniCore { | ||
209 | let mut res = MiniCore { activated_flags: Vec::new(), valid_flags: Vec::new() }; | ||
210 | |||
211 | let line = line.strip_prefix("//- minicore:").unwrap().trim(); | ||
212 | for entry in line.split(", ") { | ||
213 | if res.has_flag(entry) { | ||
214 | panic!("duplicate minicore flag: {:?}", entry) | ||
215 | } | ||
216 | res.activated_flags.push(entry.to_string()) | ||
217 | } | ||
218 | |||
219 | res | ||
220 | } | ||
221 | |||
222 | /// Strips parts of minicore.rs which are flagged by inactive flags. | ||
223 | /// | ||
224 | /// This is probably over-engineered to support flags dependencies. | ||
225 | pub fn source_code(mut self) -> String { | ||
226 | let mut buf = String::new(); | ||
227 | let raw_mini_core = include_str!("./minicore.rs"); | ||
228 | let mut lines = raw_mini_core.split_inclusive('\n'); | ||
229 | |||
230 | let mut parsing_flags = false; | ||
231 | let mut implications = Vec::new(); | ||
232 | |||
233 | // Parse `//!` preamble and extract flags and dependencies. | ||
234 | for line in lines.by_ref() { | ||
235 | let line = match line.strip_prefix("//!") { | ||
236 | Some(it) => it, | ||
237 | None => { | ||
238 | assert!(line.trim().is_empty()); | ||
239 | break; | ||
240 | } | ||
241 | }; | ||
242 | |||
243 | if parsing_flags { | ||
244 | let (flag, deps) = line.split_once(':').unwrap(); | ||
245 | let flag = flag.trim(); | ||
246 | self.valid_flags.push(flag.to_string()); | ||
247 | for dep in deps.split(", ") { | ||
248 | let dep = dep.trim(); | ||
249 | if !dep.is_empty() { | ||
250 | self.assert_valid_flag(dep); | ||
251 | implications.push((flag, dep)); | ||
252 | } | ||
253 | } | ||
254 | } | ||
255 | |||
256 | if line.contains("Available flags:") { | ||
257 | parsing_flags = true; | ||
258 | } | ||
259 | } | ||
260 | |||
261 | for flag in &self.activated_flags { | ||
262 | self.assert_valid_flag(flag); | ||
263 | } | ||
264 | |||
265 | // Fixed point loop to compute transitive closure of flags. | ||
266 | loop { | ||
267 | let mut changed = false; | ||
268 | for &(u, v) in implications.iter() { | ||
269 | if self.has_flag(u) && !self.has_flag(v) { | ||
270 | self.activated_flags.push(v.to_string()); | ||
271 | changed = true; | ||
272 | } | ||
273 | } | ||
274 | if !changed { | ||
275 | break; | ||
276 | } | ||
277 | } | ||
278 | |||
279 | let mut curr_region = ""; | ||
280 | let mut seen_regions = Vec::new(); | ||
281 | for line in lines { | ||
282 | let trimmed = line.trim(); | ||
283 | if let Some(region) = trimmed.strip_prefix("// region:") { | ||
284 | assert_eq!(curr_region, ""); | ||
285 | curr_region = region; | ||
286 | continue; | ||
287 | } | ||
288 | if let Some(region) = trimmed.strip_prefix("// endregion:") { | ||
289 | assert_eq!(curr_region, region); | ||
290 | curr_region = ""; | ||
291 | continue; | ||
292 | } | ||
293 | seen_regions.push(curr_region); | ||
294 | |||
295 | let mut flag = curr_region; | ||
296 | if let Some(idx) = trimmed.find("// :") { | ||
297 | flag = &trimmed[idx + "// :".len()..]; | ||
298 | } | ||
299 | |||
300 | let skip = if flag == "" { | ||
301 | false | ||
302 | } else { | ||
303 | assert!(!flag.starts_with(' '), "region marker starts with a space: {:?}", flag); | ||
304 | self.assert_valid_flag(flag); | ||
305 | !self.has_flag(flag) | ||
306 | }; | ||
307 | |||
308 | if !skip { | ||
309 | buf.push_str(line) | ||
310 | } | ||
311 | } | ||
312 | |||
313 | for flag in &self.valid_flags { | ||
314 | if !seen_regions.iter().any(|it| it == flag) { | ||
315 | panic!("unused minicore flag: {:?}", flag); | ||
316 | } | ||
317 | } | ||
318 | |||
319 | buf | ||
320 | } | ||
321 | } | ||
322 | |||
175 | #[test] | 323 | #[test] |
176 | #[should_panic] | 324 | #[should_panic] |
177 | fn parse_fixture_checks_further_indented_metadata() { | 325 | fn parse_fixture_checks_further_indented_metadata() { |
@@ -189,12 +337,14 @@ fn parse_fixture_checks_further_indented_metadata() { | |||
189 | 337 | ||
190 | #[test] | 338 | #[test] |
191 | fn parse_fixture_gets_full_meta() { | 339 | fn parse_fixture_gets_full_meta() { |
192 | let parsed = Fixture::parse( | 340 | let (mini_core, parsed) = Fixture::parse( |
193 | r" | 341 | r#" |
194 | //- /lib.rs crate:foo deps:bar,baz cfg:foo=a,bar=b,atom env:OUTDIR=path/to,OTHER=foo | 342 | //- minicore: coerce_unsized |
195 | mod m; | 343 | //- /lib.rs crate:foo deps:bar,baz cfg:foo=a,bar=b,atom env:OUTDIR=path/to,OTHER=foo |
196 | ", | 344 | mod m; |
345 | "#, | ||
197 | ); | 346 | ); |
347 | assert_eq!(mini_core.unwrap().activated_flags, vec!["coerce_unsized".to_string()]); | ||
198 | assert_eq!(1, parsed.len()); | 348 | assert_eq!(1, parsed.len()); |
199 | 349 | ||
200 | let meta = &parsed[0]; | 350 | let meta = &parsed[0]; |
diff --git a/crates/test_utils/src/lib.rs b/crates/test_utils/src/lib.rs index b2fe25f82..d55bae62a 100644 --- a/crates/test_utils/src/lib.rs +++ b/crates/test_utils/src/lib.rs | |||
@@ -23,7 +23,10 @@ use text_size::{TextRange, TextSize}; | |||
23 | pub use dissimilar::diff as __diff; | 23 | pub use dissimilar::diff as __diff; |
24 | pub use rustc_hash::FxHashMap; | 24 | pub use rustc_hash::FxHashMap; |
25 | 25 | ||
26 | pub use crate::{assert_linear::AssertLinear, fixture::Fixture}; | 26 | pub use crate::{ |
27 | assert_linear::AssertLinear, | ||
28 | fixture::{Fixture, MiniCore}, | ||
29 | }; | ||
27 | 30 | ||
28 | pub const CURSOR_MARKER: &str = "$0"; | 31 | pub const CURSOR_MARKER: &str = "$0"; |
29 | pub const ESCAPED_CURSOR_MARKER: &str = "\\$0"; | 32 | pub const ESCAPED_CURSOR_MARKER: &str = "\\$0"; |
diff --git a/crates/test_utils/src/minicore.rs b/crates/test_utils/src/minicore.rs new file mode 100644 index 000000000..5ff60178c --- /dev/null +++ b/crates/test_utils/src/minicore.rs | |||
@@ -0,0 +1,204 @@ | |||
1 | //! This is a fixture we use for tests that need lang items. | ||
2 | //! | ||
3 | //! We want to include the minimal subset of core for each test, so this file | ||
4 | //! supports "conditional compilation". Tests use the following syntax to include minicore: | ||
5 | //! | ||
6 | //! //- minicore: flag1, flag2 | ||
7 | //! | ||
8 | //! We then strip all the code marked with other flags. | ||
9 | //! | ||
10 | //! Available flags: | ||
11 | //! sized: | ||
12 | //! slice: | ||
13 | //! range: | ||
14 | //! unsize: sized | ||
15 | //! deref: sized | ||
16 | //! coerce_unsized: unsize | ||
17 | //! pin: | ||
18 | //! future: pin | ||
19 | //! option: | ||
20 | //! result: | ||
21 | |||
22 | pub mod marker { | ||
23 | // region:sized | ||
24 | #[lang = "sized"] | ||
25 | #[fundamental] | ||
26 | #[rustc_specialization_trait] | ||
27 | pub trait Sized {} | ||
28 | // endregion:sized | ||
29 | |||
30 | // region:unsize | ||
31 | #[lang = "unsize"] | ||
32 | pub trait Unsize<T: ?Sized> {} | ||
33 | // endregion:unsize | ||
34 | } | ||
35 | |||
36 | pub mod ops { | ||
37 | // region:coerce_unsized | ||
38 | mod unsize { | ||
39 | use crate::marker::Unsize; | ||
40 | |||
41 | #[lang = "coerce_unsized"] | ||
42 | pub trait CoerceUnsized<T: ?Sized> {} | ||
43 | |||
44 | impl<'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a mut U> for &'a mut T {} | ||
45 | impl<'a, 'b: 'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a U> for &'b mut T {} | ||
46 | impl<'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*mut U> for &'a mut T {} | ||
47 | impl<'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*const U> for &'a mut T {} | ||
48 | |||
49 | impl<'a, 'b: 'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a U> for &'b T {} | ||
50 | impl<'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*const U> for &'a T {} | ||
51 | |||
52 | impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*mut U> for *mut T {} | ||
53 | impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*const U> for *mut T {} | ||
54 | impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*const U> for *const T {} | ||
55 | } | ||
56 | pub use self::unsize::CoerceUnsized; | ||
57 | // endregion:coerce_unsized | ||
58 | |||
59 | // region:deref | ||
60 | mod deref { | ||
61 | #[lang = "deref"] | ||
62 | pub trait Deref { | ||
63 | #[lang = "deref_target"] | ||
64 | type Target: ?Sized; | ||
65 | fn deref(&self) -> &Self::Target; | ||
66 | } | ||
67 | } | ||
68 | pub use self::deref::Deref; | ||
69 | // endregion:deref | ||
70 | |||
71 | // region:range | ||
72 | mod range { | ||
73 | #[lang = "RangeFull"] | ||
74 | pub struct RangeFull; | ||
75 | |||
76 | #[lang = "Range"] | ||
77 | pub struct Range<Idx> { | ||
78 | pub start: Idx, | ||
79 | pub end: Idx, | ||
80 | } | ||
81 | |||
82 | #[lang = "RangeFrom"] | ||
83 | pub struct RangeFrom<Idx> { | ||
84 | pub start: Idx, | ||
85 | } | ||
86 | |||
87 | #[lang = "RangeTo"] | ||
88 | pub struct RangeTo<Idx> { | ||
89 | pub end: Idx, | ||
90 | } | ||
91 | |||
92 | #[lang = "RangeInclusive"] | ||
93 | pub struct RangeInclusive<Idx> { | ||
94 | pub(crate) start: Idx, | ||
95 | pub(crate) end: Idx, | ||
96 | pub(crate) exhausted: bool, | ||
97 | } | ||
98 | |||
99 | #[lang = "RangeToInclusive"] | ||
100 | pub struct RangeToInclusive<Idx> { | ||
101 | pub end: Idx, | ||
102 | } | ||
103 | } | ||
104 | pub use self::range::{Range, RangeFrom, RangeFull, RangeTo}; | ||
105 | pub use self::range::{RangeInclusive, RangeToInclusive}; | ||
106 | // endregion:range | ||
107 | } | ||
108 | |||
109 | // region:slice | ||
110 | pub mod slice { | ||
111 | #[lang = "slice"] | ||
112 | impl<T> [T] { | ||
113 | pub fn len(&self) -> usize { | ||
114 | loop {} | ||
115 | } | ||
116 | } | ||
117 | } | ||
118 | // endregion:slice | ||
119 | |||
120 | // region:option | ||
121 | pub mod option { | ||
122 | pub enum Option<T> { | ||
123 | #[lang = "None"] | ||
124 | None, | ||
125 | #[lang = "Some"] | ||
126 | Some(T), | ||
127 | } | ||
128 | } | ||
129 | // endregion:option | ||
130 | |||
131 | // region:result | ||
132 | pub mod result { | ||
133 | pub enum Result<T, E> { | ||
134 | #[lang = "Ok"] | ||
135 | Ok(T), | ||
136 | #[lang = "Err"] | ||
137 | Err(E), | ||
138 | } | ||
139 | } | ||
140 | // endregion:result | ||
141 | |||
142 | // region:pin | ||
143 | pub mod pin { | ||
144 | #[lang = "pin"] | ||
145 | #[fundamental] | ||
146 | pub struct Pin<P> { | ||
147 | pointer: P, | ||
148 | } | ||
149 | } | ||
150 | // endregion:pin | ||
151 | |||
152 | // region:future | ||
153 | pub mod future { | ||
154 | use crate::{ | ||
155 | pin::Pin, | ||
156 | task::{Context, Poll}, | ||
157 | }; | ||
158 | |||
159 | #[lang = "future_trait"] | ||
160 | pub trait Future { | ||
161 | type Output; | ||
162 | #[lang = "poll"] | ||
163 | fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output>; | ||
164 | } | ||
165 | } | ||
166 | pub mod task { | ||
167 | pub enum Poll<T> { | ||
168 | #[lang = "Ready"] | ||
169 | Ready(T), | ||
170 | #[lang = "Pending"] | ||
171 | Pending, | ||
172 | } | ||
173 | |||
174 | pub struct Context<'a> { | ||
175 | waker: &'a (), | ||
176 | } | ||
177 | } | ||
178 | // endregion:future | ||
179 | |||
180 | pub mod prelude { | ||
181 | pub mod v1 { | ||
182 | pub use crate::{ | ||
183 | marker::Sized, // :sized | ||
184 | option::Option::{self, None, Some}, // :option | ||
185 | result::Result::{self, Err, Ok}, // :result | ||
186 | }; | ||
187 | } | ||
188 | |||
189 | pub mod rust_2015 { | ||
190 | pub use super::v1::*; | ||
191 | } | ||
192 | |||
193 | pub mod rust_2018 { | ||
194 | pub use super::v1::*; | ||
195 | } | ||
196 | |||
197 | pub mod rust_2021 { | ||
198 | pub use super::v1::*; | ||
199 | } | ||
200 | } | ||
201 | |||
202 | #[prelude_import] | ||
203 | #[allow(unused)] | ||
204 | use prelude::v1::*; | ||