diff options
Diffstat (limited to 'crates')
-rw-r--r-- | crates/assists/src/handlers/qualify_path.rs | 2 | ||||
-rw-r--r-- | crates/base_db/src/input.rs | 2 | ||||
-rw-r--r-- | crates/completion/src/completions/flyimport.rs | 12 | ||||
-rw-r--r-- | crates/completion/src/render.rs | 64 | ||||
-rw-r--r-- | crates/completion/src/render/const_.rs | 5 | ||||
-rw-r--r-- | crates/completion/src/render/function.rs | 4 | ||||
-rw-r--r-- | crates/completion/src/render/type_alias.rs | 5 | ||||
-rw-r--r-- | crates/completion/src/test_utils.rs | 3 | ||||
-rw-r--r-- | crates/hir/src/code_model.rs | 19 | ||||
-rw-r--r-- | crates/ide/src/hover.rs | 7 | ||||
-rw-r--r-- | crates/ide/src/runnables.rs | 202 | ||||
-rw-r--r-- | crates/mbe/src/syntax_bridge.rs | 26 | ||||
-rw-r--r-- | crates/parser/src/event.rs | 5 | ||||
-rw-r--r-- | crates/stdx/src/lib.rs | 2 |
14 files changed, 237 insertions, 121 deletions
diff --git a/crates/assists/src/handlers/qualify_path.rs b/crates/assists/src/handlers/qualify_path.rs index af8a11d03..b0b0d31b4 100644 --- a/crates/assists/src/handlers/qualify_path.rs +++ b/crates/assists/src/handlers/qualify_path.rs | |||
@@ -1,6 +1,6 @@ | |||
1 | use std::iter; | 1 | use std::iter; |
2 | 2 | ||
3 | use hir::AsName; | 3 | use hir::{AsAssocItem, AsName}; |
4 | use ide_db::helpers::{import_assets::ImportCandidate, mod_path_to_ast}; | 4 | use ide_db::helpers::{import_assets::ImportCandidate, mod_path_to_ast}; |
5 | use ide_db::RootDatabase; | 5 | use ide_db::RootDatabase; |
6 | use syntax::{ | 6 | use syntax::{ |
diff --git a/crates/base_db/src/input.rs b/crates/base_db/src/input.rs index 2dd8fbe67..b5f7e4200 100644 --- a/crates/base_db/src/input.rs +++ b/crates/base_db/src/input.rs | |||
@@ -178,7 +178,7 @@ pub struct CrateData { | |||
178 | pub root_file_id: FileId, | 178 | pub root_file_id: FileId, |
179 | pub edition: Edition, | 179 | pub edition: Edition, |
180 | /// A name used in the package's project declaration: for Cargo projects, | 180 | /// A name used in the package's project declaration: for Cargo projects, |
181 | /// it's [package].name, can be different for other project types or even | 181 | /// its `[package].name` can be different for other project types or even |
182 | /// absent (a dummy crate for the code snippet, for example). | 182 | /// absent (a dummy crate for the code snippet, for example). |
183 | /// | 183 | /// |
184 | /// For purposes of analysis, crates are anonymous (only names in | 184 | /// For purposes of analysis, crates are anonymous (only names in |
diff --git a/crates/completion/src/completions/flyimport.rs b/crates/completion/src/completions/flyimport.rs index 47e797ac8..dc0b38a16 100644 --- a/crates/completion/src/completions/flyimport.rs +++ b/crates/completion/src/completions/flyimport.rs | |||
@@ -48,7 +48,7 @@ | |||
48 | //! Note that having this flag set to `true` does not guarantee that the feature is enabled: your client needs to have the corredponding | 48 | //! Note that having this flag set to `true` does not guarantee that the feature is enabled: your client needs to have the corredponding |
49 | //! capability enabled. | 49 | //! capability enabled. |
50 | 50 | ||
51 | use hir::{ModPath, ScopeDef}; | 51 | use hir::{AsAssocItem, ModPath, ScopeDef}; |
52 | use ide_db::helpers::{ | 52 | use ide_db::helpers::{ |
53 | import_assets::{ImportAssets, ImportCandidate}, | 53 | import_assets::{ImportAssets, ImportCandidate}, |
54 | insert_use::ImportScope, | 54 | insert_use::ImportScope, |
@@ -601,11 +601,12 @@ fn main() { | |||
601 | } | 601 | } |
602 | 602 | ||
603 | #[test] | 603 | #[test] |
604 | fn zero_input_assoc_item_completion() { | 604 | fn zero_input_deprecated_assoc_item_completion() { |
605 | check( | 605 | check( |
606 | r#" | 606 | r#" |
607 | //- /lib.rs crate:dep | 607 | //- /lib.rs crate:dep |
608 | pub mod test_mod { | 608 | pub mod test_mod { |
609 | #[deprecated] | ||
609 | pub trait TestTrait { | 610 | pub trait TestTrait { |
610 | const SPECIAL_CONST: u8; | 611 | const SPECIAL_CONST: u8; |
611 | type HumbleType; | 612 | type HumbleType; |
@@ -628,7 +629,7 @@ fn main() { | |||
628 | } | 629 | } |
629 | "#, | 630 | "#, |
630 | expect![[r#" | 631 | expect![[r#" |
631 | me random_method() (dep::test_mod::TestTrait) fn random_method(&self) | 632 | me random_method() (dep::test_mod::TestTrait) fn random_method(&self) DEPRECATED |
632 | "#]], | 633 | "#]], |
633 | ); | 634 | ); |
634 | 635 | ||
@@ -636,6 +637,7 @@ fn main() { | |||
636 | r#" | 637 | r#" |
637 | //- /lib.rs crate:dep | 638 | //- /lib.rs crate:dep |
638 | pub mod test_mod { | 639 | pub mod test_mod { |
640 | #[deprecated] | ||
639 | pub trait TestTrait { | 641 | pub trait TestTrait { |
640 | const SPECIAL_CONST: u8; | 642 | const SPECIAL_CONST: u8; |
641 | type HumbleType; | 643 | type HumbleType; |
@@ -657,8 +659,8 @@ fn main() { | |||
657 | } | 659 | } |
658 | "#, | 660 | "#, |
659 | expect![[r#" | 661 | expect![[r#" |
660 | ct SPECIAL_CONST (dep::test_mod::TestTrait) | 662 | ct SPECIAL_CONST (dep::test_mod::TestTrait) DEPRECATED |
661 | fn weird_function() (dep::test_mod::TestTrait) fn weird_function() | 663 | fn weird_function() (dep::test_mod::TestTrait) fn weird_function() DEPRECATED |
662 | "#]], | 664 | "#]], |
663 | ); | 665 | ); |
664 | } | 666 | } |
diff --git a/crates/completion/src/render.rs b/crates/completion/src/render.rs index 4b3c9702a..4f622d28a 100644 --- a/crates/completion/src/render.rs +++ b/crates/completion/src/render.rs | |||
@@ -10,7 +10,9 @@ pub(crate) mod type_alias; | |||
10 | 10 | ||
11 | mod builder_ext; | 11 | mod builder_ext; |
12 | 12 | ||
13 | use hir::{Documentation, HasAttrs, HirDisplay, ModuleDef, Mutability, ScopeDef, Type}; | 13 | use hir::{ |
14 | AsAssocItem, Documentation, HasAttrs, HirDisplay, ModuleDef, Mutability, ScopeDef, Type, | ||
15 | }; | ||
14 | use ide_db::{helpers::SnippetCap, RootDatabase}; | 16 | use ide_db::{helpers::SnippetCap, RootDatabase}; |
15 | use syntax::TextRange; | 17 | use syntax::TextRange; |
16 | use test_utils::mark; | 18 | use test_utils::mark; |
@@ -87,7 +89,24 @@ impl<'a> RenderContext<'a> { | |||
87 | } | 89 | } |
88 | 90 | ||
89 | fn is_deprecated(&self, node: impl HasAttrs) -> bool { | 91 | fn is_deprecated(&self, node: impl HasAttrs) -> bool { |
90 | node.attrs(self.db()).by_key("deprecated").exists() | 92 | let attrs = node.attrs(self.db()); |
93 | attrs.by_key("deprecated").exists() || attrs.by_key("rustc_deprecated").exists() | ||
94 | } | ||
95 | |||
96 | fn is_deprecated_assoc_item(&self, as_assoc_item: impl AsAssocItem) -> bool { | ||
97 | let db = self.db(); | ||
98 | let assoc = match as_assoc_item.as_assoc_item(db) { | ||
99 | Some(assoc) => assoc, | ||
100 | None => return false, | ||
101 | }; | ||
102 | |||
103 | let is_assoc_deprecated = match assoc { | ||
104 | hir::AssocItem::Function(it) => self.is_deprecated(it), | ||
105 | hir::AssocItem::Const(it) => self.is_deprecated(it), | ||
106 | hir::AssocItem::TypeAlias(it) => self.is_deprecated(it), | ||
107 | }; | ||
108 | is_assoc_deprecated | ||
109 | || assoc.containing_trait(db).map(|trait_| self.is_deprecated(trait_)).unwrap_or(false) | ||
91 | } | 110 | } |
92 | 111 | ||
93 | fn docs(&self, node: impl HasAttrs) -> Option<Documentation> { | 112 | fn docs(&self, node: impl HasAttrs) -> Option<Documentation> { |
@@ -206,8 +225,6 @@ impl<'a> Render<'a> { | |||
206 | } | 225 | } |
207 | }; | 226 | }; |
208 | 227 | ||
209 | let docs = self.docs(resolution); | ||
210 | |||
211 | let mut item = | 228 | let mut item = |
212 | CompletionItem::new(completion_kind, self.ctx.source_range(), local_name.clone()); | 229 | CompletionItem::new(completion_kind, self.ctx.source_range(), local_name.clone()); |
213 | if let ScopeDef::Local(local) = resolution { | 230 | if let ScopeDef::Local(local) = resolution { |
@@ -253,13 +270,14 @@ impl<'a> Render<'a> { | |||
253 | } | 270 | } |
254 | } | 271 | } |
255 | 272 | ||
256 | let item = item | 273 | Some( |
257 | .kind(kind) | 274 | item.kind(kind) |
258 | .add_import(import_to_add) | 275 | .add_import(import_to_add) |
259 | .set_documentation(docs) | 276 | .set_ref_match(ref_match) |
260 | .set_ref_match(ref_match) | 277 | .set_documentation(self.docs(resolution)) |
261 | .build(); | 278 | .set_deprecated(self.is_deprecated(resolution)) |
262 | Some(item) | 279 | .build(), |
280 | ) | ||
263 | } | 281 | } |
264 | 282 | ||
265 | fn docs(&self, resolution: &ScopeDef) -> Option<Documentation> { | 283 | fn docs(&self, resolution: &ScopeDef) -> Option<Documentation> { |
@@ -275,6 +293,16 @@ impl<'a> Render<'a> { | |||
275 | _ => None, | 293 | _ => None, |
276 | } | 294 | } |
277 | } | 295 | } |
296 | |||
297 | fn is_deprecated(&self, resolution: &ScopeDef) -> bool { | ||
298 | match resolution { | ||
299 | ScopeDef::ModuleDef(it) => self.ctx.is_deprecated_assoc_item(*it), | ||
300 | ScopeDef::MacroDef(it) => self.ctx.is_deprecated(*it), | ||
301 | ScopeDef::GenericParam(it) => self.ctx.is_deprecated(*it), | ||
302 | ScopeDef::AdtSelfType(it) => self.ctx.is_deprecated(*it), | ||
303 | _ => false, | ||
304 | } | ||
305 | } | ||
278 | } | 306 | } |
279 | 307 | ||
280 | fn compute_score_from_active( | 308 | fn compute_score_from_active( |
@@ -485,7 +513,7 @@ fn main() { let _: m::Spam = S$0 } | |||
485 | r#" | 513 | r#" |
486 | #[deprecated] | 514 | #[deprecated] |
487 | fn something_deprecated() {} | 515 | fn something_deprecated() {} |
488 | #[deprecated(since = "1.0.0")] | 516 | #[rustc_deprecated(since = "1.0.0")] |
489 | fn something_else_deprecated() {} | 517 | fn something_else_deprecated() {} |
490 | 518 | ||
491 | fn main() { som$0 } | 519 | fn main() { som$0 } |
@@ -494,8 +522,8 @@ fn main() { som$0 } | |||
494 | [ | 522 | [ |
495 | CompletionItem { | 523 | CompletionItem { |
496 | label: "main()", | 524 | label: "main()", |
497 | source_range: 121..124, | 525 | source_range: 127..130, |
498 | delete: 121..124, | 526 | delete: 127..130, |
499 | insert: "main()$0", | 527 | insert: "main()$0", |
500 | kind: Function, | 528 | kind: Function, |
501 | lookup: "main", | 529 | lookup: "main", |
@@ -503,8 +531,8 @@ fn main() { som$0 } | |||
503 | }, | 531 | }, |
504 | CompletionItem { | 532 | CompletionItem { |
505 | label: "something_deprecated()", | 533 | label: "something_deprecated()", |
506 | source_range: 121..124, | 534 | source_range: 127..130, |
507 | delete: 121..124, | 535 | delete: 127..130, |
508 | insert: "something_deprecated()$0", | 536 | insert: "something_deprecated()$0", |
509 | kind: Function, | 537 | kind: Function, |
510 | lookup: "something_deprecated", | 538 | lookup: "something_deprecated", |
@@ -513,8 +541,8 @@ fn main() { som$0 } | |||
513 | }, | 541 | }, |
514 | CompletionItem { | 542 | CompletionItem { |
515 | label: "something_else_deprecated()", | 543 | label: "something_else_deprecated()", |
516 | source_range: 121..124, | 544 | source_range: 127..130, |
517 | delete: 121..124, | 545 | delete: 127..130, |
518 | insert: "something_else_deprecated()$0", | 546 | insert: "something_else_deprecated()$0", |
519 | kind: Function, | 547 | kind: Function, |
520 | lookup: "something_else_deprecated", | 548 | lookup: "something_else_deprecated", |
diff --git a/crates/completion/src/render/const_.rs b/crates/completion/src/render/const_.rs index ce924f309..e46452d4e 100644 --- a/crates/completion/src/render/const_.rs +++ b/crates/completion/src/render/const_.rs | |||
@@ -38,7 +38,10 @@ impl<'a> ConstRender<'a> { | |||
38 | let item = CompletionItem::new(CompletionKind::Reference, self.ctx.source_range(), name) | 38 | let item = CompletionItem::new(CompletionKind::Reference, self.ctx.source_range(), name) |
39 | .kind(CompletionItemKind::Const) | 39 | .kind(CompletionItemKind::Const) |
40 | .set_documentation(self.ctx.docs(self.const_)) | 40 | .set_documentation(self.ctx.docs(self.const_)) |
41 | .set_deprecated(self.ctx.is_deprecated(self.const_)) | 41 | .set_deprecated( |
42 | self.ctx.is_deprecated(self.const_) | ||
43 | || self.ctx.is_deprecated_assoc_item(self.const_), | ||
44 | ) | ||
42 | .detail(detail) | 45 | .detail(detail) |
43 | .build(); | 46 | .build(); |
44 | 47 | ||
diff --git a/crates/completion/src/render/function.rs b/crates/completion/src/render/function.rs index f5b0ce3e3..8f4c66211 100644 --- a/crates/completion/src/render/function.rs +++ b/crates/completion/src/render/function.rs | |||
@@ -44,7 +44,9 @@ impl<'a> FunctionRender<'a> { | |||
44 | CompletionItem::new(CompletionKind::Reference, self.ctx.source_range(), self.name.clone()) | 44 | CompletionItem::new(CompletionKind::Reference, self.ctx.source_range(), self.name.clone()) |
45 | .kind(self.kind()) | 45 | .kind(self.kind()) |
46 | .set_documentation(self.ctx.docs(self.func)) | 46 | .set_documentation(self.ctx.docs(self.func)) |
47 | .set_deprecated(self.ctx.is_deprecated(self.func)) | 47 | .set_deprecated( |
48 | self.ctx.is_deprecated(self.func) || self.ctx.is_deprecated_assoc_item(self.func), | ||
49 | ) | ||
48 | .detail(self.detail()) | 50 | .detail(self.detail()) |
49 | .add_call_parens(self.ctx.completion, self.name, params) | 51 | .add_call_parens(self.ctx.completion, self.name, params) |
50 | .add_import(import_to_add) | 52 | .add_import(import_to_add) |
diff --git a/crates/completion/src/render/type_alias.rs b/crates/completion/src/render/type_alias.rs index 69b445b9c..29287143a 100644 --- a/crates/completion/src/render/type_alias.rs +++ b/crates/completion/src/render/type_alias.rs | |||
@@ -38,7 +38,10 @@ impl<'a> TypeAliasRender<'a> { | |||
38 | let item = CompletionItem::new(CompletionKind::Reference, self.ctx.source_range(), name) | 38 | let item = CompletionItem::new(CompletionKind::Reference, self.ctx.source_range(), name) |
39 | .kind(CompletionItemKind::TypeAlias) | 39 | .kind(CompletionItemKind::TypeAlias) |
40 | .set_documentation(self.ctx.docs(self.type_alias)) | 40 | .set_documentation(self.ctx.docs(self.type_alias)) |
41 | .set_deprecated(self.ctx.is_deprecated(self.type_alias)) | 41 | .set_deprecated( |
42 | self.ctx.is_deprecated(self.type_alias) | ||
43 | || self.ctx.is_deprecated_assoc_item(self.type_alias), | ||
44 | ) | ||
42 | .detail(detail) | 45 | .detail(detail) |
43 | .build(); | 46 | .build(); |
44 | 47 | ||
diff --git a/crates/completion/src/test_utils.rs b/crates/completion/src/test_utils.rs index 3faf861b9..baff83305 100644 --- a/crates/completion/src/test_utils.rs +++ b/crates/completion/src/test_utils.rs | |||
@@ -83,6 +83,9 @@ pub(crate) fn completion_list_with_config( | |||
83 | let width = label_width.saturating_sub(monospace_width(it.label())); | 83 | let width = label_width.saturating_sub(monospace_width(it.label())); |
84 | format_to!(buf, "{:width$} {}", "", detail, width = width); | 84 | format_to!(buf, "{:width$} {}", "", detail, width = width); |
85 | } | 85 | } |
86 | if it.deprecated() { | ||
87 | format_to!(buf, " DEPRECATED"); | ||
88 | } | ||
86 | format_to!(buf, "\n"); | 89 | format_to!(buf, "\n"); |
87 | buf | 90 | buf |
88 | }) | 91 | }) |
diff --git a/crates/hir/src/code_model.rs b/crates/hir/src/code_model.rs index 6f48322db..a4141e111 100644 --- a/crates/hir/src/code_model.rs +++ b/crates/hir/src/code_model.rs | |||
@@ -272,15 +272,6 @@ impl ModuleDef { | |||
272 | 272 | ||
273 | hir_ty::diagnostics::validate_module_item(db, module.id.krate, id, sink) | 273 | hir_ty::diagnostics::validate_module_item(db, module.id.krate, id, sink) |
274 | } | 274 | } |
275 | |||
276 | pub fn as_assoc_item(self, db: &dyn HirDatabase) -> Option<AssocItem> { | ||
277 | match self { | ||
278 | ModuleDef::Function(f) => f.as_assoc_item(db), | ||
279 | ModuleDef::Const(c) => c.as_assoc_item(db), | ||
280 | ModuleDef::TypeAlias(t) => t.as_assoc_item(db), | ||
281 | _ => None, | ||
282 | } | ||
283 | } | ||
284 | } | 275 | } |
285 | 276 | ||
286 | impl Module { | 277 | impl Module { |
@@ -1060,6 +1051,16 @@ impl AsAssocItem for TypeAlias { | |||
1060 | as_assoc_item(db, AssocItem::TypeAlias, self.id) | 1051 | as_assoc_item(db, AssocItem::TypeAlias, self.id) |
1061 | } | 1052 | } |
1062 | } | 1053 | } |
1054 | impl AsAssocItem for ModuleDef { | ||
1055 | fn as_assoc_item(self, db: &dyn HirDatabase) -> Option<AssocItem> { | ||
1056 | match self { | ||
1057 | ModuleDef::Function(it) => it.as_assoc_item(db), | ||
1058 | ModuleDef::Const(it) => it.as_assoc_item(db), | ||
1059 | ModuleDef::TypeAlias(it) => it.as_assoc_item(db), | ||
1060 | _ => None, | ||
1061 | } | ||
1062 | } | ||
1063 | } | ||
1063 | fn as_assoc_item<ID, DEF, CTOR, AST>(db: &dyn HirDatabase, ctor: CTOR, id: ID) -> Option<AssocItem> | 1064 | fn as_assoc_item<ID, DEF, CTOR, AST>(db: &dyn HirDatabase, ctor: CTOR, id: ID) -> Option<AssocItem> |
1064 | where | 1065 | where |
1065 | ID: Lookup<Data = AssocItemLoc<AST>>, | 1066 | ID: Lookup<Data = AssocItemLoc<AST>>, |
diff --git a/crates/ide/src/hover.rs b/crates/ide/src/hover.rs index 2024acd94..44ebdbd35 100644 --- a/crates/ide/src/hover.rs +++ b/crates/ide/src/hover.rs | |||
@@ -182,12 +182,7 @@ fn runnable_action( | |||
182 | ) -> Option<HoverAction> { | 182 | ) -> Option<HoverAction> { |
183 | match def { | 183 | match def { |
184 | Definition::ModuleDef(it) => match it { | 184 | Definition::ModuleDef(it) => match it { |
185 | ModuleDef::Module(it) => match it.definition_source(sema.db).value { | 185 | ModuleDef::Module(it) => runnable_mod(&sema, it).map(|it| HoverAction::Runnable(it)), |
186 | ModuleSource::Module(it) => { | ||
187 | runnable_mod(&sema, it).map(|it| HoverAction::Runnable(it)) | ||
188 | } | ||
189 | _ => None, | ||
190 | }, | ||
191 | ModuleDef::Function(func) => { | 186 | ModuleDef::Function(func) => { |
192 | let src = func.source(sema.db)?; | 187 | let src = func.source(sema.db)?; |
193 | if src.file_id != file_id.into() { | 188 | if src.file_id != file_id.into() { |
diff --git a/crates/ide/src/runnables.rs b/crates/ide/src/runnables.rs index f5ee7de86..8976f1080 100644 --- a/crates/ide/src/runnables.rs +++ b/crates/ide/src/runnables.rs | |||
@@ -6,7 +6,7 @@ use hir::{AsAssocItem, HasAttrs, HasSource, Semantics}; | |||
6 | use ide_db::{defs::Definition, RootDatabase}; | 6 | use ide_db::{defs::Definition, RootDatabase}; |
7 | use itertools::Itertools; | 7 | use itertools::Itertools; |
8 | use syntax::{ | 8 | use syntax::{ |
9 | ast::{self, AstNode, AttrsOwner, ModuleItemOwner}, | 9 | ast::{self, AstNode, AttrsOwner}, |
10 | match_ast, SyntaxNode, | 10 | match_ast, SyntaxNode, |
11 | }; | 11 | }; |
12 | 12 | ||
@@ -95,27 +95,44 @@ impl Runnable { | |||
95 | // |=== | 95 | // |=== |
96 | pub(crate) fn runnables(db: &RootDatabase, file_id: FileId) -> Vec<Runnable> { | 96 | pub(crate) fn runnables(db: &RootDatabase, file_id: FileId) -> Vec<Runnable> { |
97 | let sema = Semantics::new(db); | 97 | let sema = Semantics::new(db); |
98 | let source_file = sema.parse(file_id); | 98 | let module = match sema.to_module_def(file_id) { |
99 | source_file | 99 | None => return vec![], |
100 | .syntax() | 100 | Some(it) => it, |
101 | .descendants() | 101 | }; |
102 | .filter_map(|item| { | 102 | |
103 | let runnable = match_ast! { | 103 | runnables_mod(&sema, module) |
104 | match item { | 104 | } |
105 | ast::Fn(func) => { | 105 | |
106 | let def = sema.to_def(&func)?; | 106 | fn runnables_mod(sema: &Semantics<RootDatabase>, module: hir::Module) -> Vec<Runnable> { |
107 | runnable_fn(&sema, def) | 107 | let mut res: Vec<Runnable> = module |
108 | }, | 108 | .declarations(sema.db) |
109 | ast::Module(it) => runnable_mod(&sema, it), | 109 | .into_iter() |
110 | _ => None, | 110 | .filter_map(|def| { |
111 | } | 111 | let runnable = match def { |
112 | }; | 112 | hir::ModuleDef::Module(it) => runnable_mod(&sema, it), |
113 | runnable.or_else(|| match doc_owner_to_def(&sema, item)? { | 113 | hir::ModuleDef::Function(it) => runnable_fn(&sema, it), |
114 | Definition::ModuleDef(def) => module_def_doctest(&sema, def), | ||
115 | _ => None, | 114 | _ => None, |
116 | }) | 115 | }; |
116 | runnable.or_else(|| module_def_doctest(&sema, def)) | ||
117 | }) | 117 | }) |
118 | .collect() | 118 | .collect(); |
119 | |||
120 | res.extend(module.impl_defs(sema.db).into_iter().flat_map(|it| it.items(sema.db)).filter_map( | ||
121 | |def| match def { | ||
122 | hir::AssocItem::Function(it) => { | ||
123 | runnable_fn(&sema, it).or_else(|| module_def_doctest(&sema, it.into())) | ||
124 | } | ||
125 | hir::AssocItem::Const(it) => module_def_doctest(&sema, it.into()), | ||
126 | hir::AssocItem::TypeAlias(it) => module_def_doctest(&sema, it.into()), | ||
127 | }, | ||
128 | )); | ||
129 | |||
130 | res.extend(module.declarations(sema.db).into_iter().flat_map(|def| match def { | ||
131 | hir::ModuleDef::Module(it) => runnables_mod(sema, it), | ||
132 | _ => vec![], | ||
133 | })); | ||
134 | |||
135 | res | ||
119 | } | 136 | } |
120 | 137 | ||
121 | pub(crate) fn runnable_fn(sema: &Semantics<RootDatabase>, def: hir::Function) -> Option<Runnable> { | 138 | pub(crate) fn runnable_fn(sema: &Semantics<RootDatabase>, def: hir::Function) -> Option<Runnable> { |
@@ -150,26 +167,16 @@ pub(crate) fn runnable_fn(sema: &Semantics<RootDatabase>, def: hir::Function) -> | |||
150 | Some(Runnable { nav, kind, cfg }) | 167 | Some(Runnable { nav, kind, cfg }) |
151 | } | 168 | } |
152 | 169 | ||
153 | pub(crate) fn runnable_mod( | 170 | pub(crate) fn runnable_mod(sema: &Semantics<RootDatabase>, def: hir::Module) -> Option<Runnable> { |
154 | sema: &Semantics<RootDatabase>, | 171 | if !has_test_function_or_multiple_test_submodules(sema, &def) { |
155 | module: ast::Module, | ||
156 | ) -> Option<Runnable> { | ||
157 | if !has_test_function_or_multiple_test_submodules(&module) { | ||
158 | return None; | 172 | return None; |
159 | } | 173 | } |
160 | let module_def = sema.to_def(&module)?; | 174 | let path = |
161 | 175 | def.path_to_root(sema.db).into_iter().rev().filter_map(|it| it.name(sema.db)).join("::"); | |
162 | let path = module_def | ||
163 | .path_to_root(sema.db) | ||
164 | .into_iter() | ||
165 | .rev() | ||
166 | .filter_map(|it| it.name(sema.db)) | ||
167 | .join("::"); | ||
168 | 176 | ||
169 | let def = sema.to_def(&module)?; | ||
170 | let attrs = def.attrs(sema.db); | 177 | let attrs = def.attrs(sema.db); |
171 | let cfg = attrs.cfg(); | 178 | let cfg = attrs.cfg(); |
172 | let nav = module_def.to_nav(sema.db); | 179 | let nav = def.to_nav(sema.db); |
173 | Some(Runnable { nav, kind: RunnableKind::TestMod { path }, cfg }) | 180 | Some(Runnable { nav, kind: RunnableKind::TestMod { path }, cfg }) |
174 | } | 181 | } |
175 | 182 | ||
@@ -289,30 +296,31 @@ fn has_runnable_doc_test(attrs: &hir::Attrs) -> bool { | |||
289 | 296 | ||
290 | // We could create runnables for modules with number_of_test_submodules > 0, | 297 | // We could create runnables for modules with number_of_test_submodules > 0, |
291 | // but that bloats the runnables for no real benefit, since all tests can be run by the submodule already | 298 | // but that bloats the runnables for no real benefit, since all tests can be run by the submodule already |
292 | fn has_test_function_or_multiple_test_submodules(module: &ast::Module) -> bool { | 299 | fn has_test_function_or_multiple_test_submodules( |
293 | if let Some(item_list) = module.item_list() { | 300 | sema: &Semantics<RootDatabase>, |
294 | let mut number_of_test_submodules = 0; | 301 | module: &hir::Module, |
295 | 302 | ) -> bool { | |
296 | for item in item_list.items() { | 303 | let mut number_of_test_submodules = 0; |
297 | match item { | 304 | |
298 | ast::Item::Fn(f) => { | 305 | for item in module.declarations(sema.db) { |
299 | if test_related_attribute(&f).is_some() { | 306 | match item { |
307 | hir::ModuleDef::Function(f) => { | ||
308 | if let Some(it) = f.source(sema.db) { | ||
309 | if test_related_attribute(&it.value).is_some() { | ||
300 | return true; | 310 | return true; |
301 | } | 311 | } |
302 | } | 312 | } |
303 | ast::Item::Module(submodule) => { | 313 | } |
304 | if has_test_function_or_multiple_test_submodules(&submodule) { | 314 | hir::ModuleDef::Module(submodule) => { |
305 | number_of_test_submodules += 1; | 315 | if has_test_function_or_multiple_test_submodules(sema, &submodule) { |
306 | } | 316 | number_of_test_submodules += 1; |
307 | } | 317 | } |
308 | _ => (), | ||
309 | } | 318 | } |
319 | _ => (), | ||
310 | } | 320 | } |
311 | |||
312 | number_of_test_submodules > 1 | ||
313 | } else { | ||
314 | false | ||
315 | } | 321 | } |
322 | |||
323 | number_of_test_submodules > 1 | ||
316 | } | 324 | } |
317 | 325 | ||
318 | #[cfg(test)] | 326 | #[cfg(test)] |
@@ -753,6 +761,21 @@ mod root_tests { | |||
753 | file_id: FileId( | 761 | file_id: FileId( |
754 | 0, | 762 | 0, |
755 | ), | 763 | ), |
764 | full_range: 202..286, | ||
765 | focus_range: 206..220, | ||
766 | name: "nested_tests_2", | ||
767 | kind: Module, | ||
768 | }, | ||
769 | kind: TestMod { | ||
770 | path: "root_tests::nested_tests_0::nested_tests_2", | ||
771 | }, | ||
772 | cfg: None, | ||
773 | }, | ||
774 | Runnable { | ||
775 | nav: NavigationTarget { | ||
776 | file_id: FileId( | ||
777 | 0, | ||
778 | ), | ||
756 | full_range: 84..126, | 779 | full_range: 84..126, |
757 | focus_range: 107..121, | 780 | focus_range: 107..121, |
758 | name: "nested_test_11", | 781 | name: "nested_test_11", |
@@ -793,21 +816,6 @@ mod root_tests { | |||
793 | file_id: FileId( | 816 | file_id: FileId( |
794 | 0, | 817 | 0, |
795 | ), | 818 | ), |
796 | full_range: 202..286, | ||
797 | focus_range: 206..220, | ||
798 | name: "nested_tests_2", | ||
799 | kind: Module, | ||
800 | }, | ||
801 | kind: TestMod { | ||
802 | path: "root_tests::nested_tests_0::nested_tests_2", | ||
803 | }, | ||
804 | cfg: None, | ||
805 | }, | ||
806 | Runnable { | ||
807 | nav: NavigationTarget { | ||
808 | file_id: FileId( | ||
809 | 0, | ||
810 | ), | ||
811 | full_range: 235..276, | 819 | full_range: 235..276, |
812 | focus_range: 258..271, | 820 | focus_range: 258..271, |
813 | name: "nested_test_2", | 821 | name: "nested_test_2", |
@@ -982,4 +990,64 @@ impl Foo { | |||
982 | "#]], | 990 | "#]], |
983 | ); | 991 | ); |
984 | } | 992 | } |
993 | |||
994 | #[test] | ||
995 | fn test_runnables_in_macro() { | ||
996 | check( | ||
997 | r#" | ||
998 | //- /lib.rs | ||
999 | $0 | ||
1000 | macro_rules! gen { | ||
1001 | () => { | ||
1002 | #[test] | ||
1003 | fn foo_test() { | ||
1004 | } | ||
1005 | } | ||
1006 | } | ||
1007 | mod tests { | ||
1008 | gen!(); | ||
1009 | } | ||
1010 | "#, | ||
1011 | &[&TEST, &TEST], | ||
1012 | expect![[r#" | ||
1013 | [ | ||
1014 | Runnable { | ||
1015 | nav: NavigationTarget { | ||
1016 | file_id: FileId( | ||
1017 | 0, | ||
1018 | ), | ||
1019 | full_range: 90..115, | ||
1020 | focus_range: 94..99, | ||
1021 | name: "tests", | ||
1022 | kind: Module, | ||
1023 | }, | ||
1024 | kind: TestMod { | ||
1025 | path: "tests", | ||
1026 | }, | ||
1027 | cfg: None, | ||
1028 | }, | ||
1029 | Runnable { | ||
1030 | nav: NavigationTarget { | ||
1031 | file_id: FileId( | ||
1032 | 0, | ||
1033 | ), | ||
1034 | full_range: 106..113, | ||
1035 | focus_range: 106..113, | ||
1036 | name: "foo_test", | ||
1037 | kind: Function, | ||
1038 | }, | ||
1039 | kind: Test { | ||
1040 | test_id: Path( | ||
1041 | "tests::foo_test", | ||
1042 | ), | ||
1043 | attr: TestAttr { | ||
1044 | ignore: false, | ||
1045 | }, | ||
1046 | }, | ||
1047 | cfg: None, | ||
1048 | }, | ||
1049 | ] | ||
1050 | "#]], | ||
1051 | ); | ||
1052 | } | ||
985 | } | 1053 | } |
diff --git a/crates/mbe/src/syntax_bridge.rs b/crates/mbe/src/syntax_bridge.rs index 2a41d8167..51002e7b8 100644 --- a/crates/mbe/src/syntax_bridge.rs +++ b/crates/mbe/src/syntax_bridge.rs | |||
@@ -16,16 +16,18 @@ use crate::ExpandError; | |||
16 | #[derive(Debug, PartialEq, Eq, Clone, Copy)] | 16 | #[derive(Debug, PartialEq, Eq, Clone, Copy)] |
17 | pub enum TokenTextRange { | 17 | pub enum TokenTextRange { |
18 | Token(TextRange), | 18 | Token(TextRange), |
19 | Delimiter(TextRange, TextRange), | 19 | Delimiter(TextRange), |
20 | } | 20 | } |
21 | 21 | ||
22 | impl TokenTextRange { | 22 | impl TokenTextRange { |
23 | pub fn by_kind(self, kind: SyntaxKind) -> Option<TextRange> { | 23 | pub fn by_kind(self, kind: SyntaxKind) -> Option<TextRange> { |
24 | match self { | 24 | match self { |
25 | TokenTextRange::Token(it) => Some(it), | 25 | TokenTextRange::Token(it) => Some(it), |
26 | TokenTextRange::Delimiter(open, close) => match kind { | 26 | TokenTextRange::Delimiter(it) => match kind { |
27 | T!['{'] | T!['('] | T!['['] => Some(open), | 27 | T!['{'] | T!['('] | T!['['] => Some(TextRange::at(it.start(), 1.into())), |
28 | T!['}'] | T![')'] | T![']'] => Some(close), | 28 | T!['}'] | T![')'] | T![']'] => { |
29 | Some(TextRange::at(it.end() - TextSize::of('}'), 1.into())) | ||
30 | } | ||
29 | _ => None, | 31 | _ => None, |
30 | }, | 32 | }, |
31 | } | 33 | } |
@@ -114,8 +116,10 @@ impl TokenMap { | |||
114 | pub fn token_by_range(&self, relative_range: TextRange) -> Option<tt::TokenId> { | 116 | pub fn token_by_range(&self, relative_range: TextRange) -> Option<tt::TokenId> { |
115 | let &(token_id, _) = self.entries.iter().find(|(_, range)| match range { | 117 | let &(token_id, _) = self.entries.iter().find(|(_, range)| match range { |
116 | TokenTextRange::Token(it) => *it == relative_range, | 118 | TokenTextRange::Token(it) => *it == relative_range, |
117 | TokenTextRange::Delimiter(open, close) => { | 119 | TokenTextRange::Delimiter(it) => { |
118 | *open == relative_range || *close == relative_range | 120 | let open = TextRange::at(it.start(), 1.into()); |
121 | let close = TextRange::at(it.end() - TextSize::of('}'), 1.into()); | ||
122 | open == relative_range || close == relative_range | ||
119 | } | 123 | } |
120 | })?; | 124 | })?; |
121 | Some(token_id) | 125 | Some(token_id) |
@@ -137,15 +141,17 @@ impl TokenMap { | |||
137 | close_relative_range: TextRange, | 141 | close_relative_range: TextRange, |
138 | ) -> usize { | 142 | ) -> usize { |
139 | let res = self.entries.len(); | 143 | let res = self.entries.len(); |
140 | self.entries | 144 | let cover = open_relative_range.cover(close_relative_range); |
141 | .push((token_id, TokenTextRange::Delimiter(open_relative_range, close_relative_range))); | 145 | |
146 | self.entries.push((token_id, TokenTextRange::Delimiter(cover))); | ||
142 | res | 147 | res |
143 | } | 148 | } |
144 | 149 | ||
145 | fn update_close_delim(&mut self, idx: usize, close_relative_range: TextRange) { | 150 | fn update_close_delim(&mut self, idx: usize, close_relative_range: TextRange) { |
146 | let (_, token_text_range) = &mut self.entries[idx]; | 151 | let (_, token_text_range) = &mut self.entries[idx]; |
147 | if let TokenTextRange::Delimiter(dim, _) = token_text_range { | 152 | if let TokenTextRange::Delimiter(dim) = token_text_range { |
148 | *token_text_range = TokenTextRange::Delimiter(*dim, close_relative_range); | 153 | let cover = dim.cover(close_relative_range); |
154 | *token_text_range = TokenTextRange::Delimiter(cover); | ||
149 | } | 155 | } |
150 | } | 156 | } |
151 | 157 | ||
diff --git a/crates/parser/src/event.rs b/crates/parser/src/event.rs index a7d06a815..903668892 100644 --- a/crates/parser/src/event.rs +++ b/crates/parser/src/event.rs | |||
@@ -38,14 +38,16 @@ pub(crate) enum Event { | |||
38 | /// | 38 | /// |
39 | /// The events for it would look like this: | 39 | /// The events for it would look like this: |
40 | /// | 40 | /// |
41 | /// | 41 | /// ```text |
42 | /// START(PATH) IDENT('foo') FINISH START(PATH) T![::] IDENT('bar') FINISH | 42 | /// START(PATH) IDENT('foo') FINISH START(PATH) T![::] IDENT('bar') FINISH |
43 | /// | /\ | 43 | /// | /\ |
44 | /// | | | 44 | /// | | |
45 | /// +------forward-parent------+ | 45 | /// +------forward-parent------+ |
46 | /// ``` | ||
46 | /// | 47 | /// |
47 | /// And the tree would look like this | 48 | /// And the tree would look like this |
48 | /// | 49 | /// |
50 | /// ```text | ||
49 | /// +--PATH---------+ | 51 | /// +--PATH---------+ |
50 | /// | | | | 52 | /// | | | |
51 | /// | | | | 53 | /// | | | |
@@ -54,6 +56,7 @@ pub(crate) enum Event { | |||
54 | /// PATH | 56 | /// PATH |
55 | /// | | 57 | /// | |
56 | /// 'foo' | 58 | /// 'foo' |
59 | /// ``` | ||
57 | /// | 60 | /// |
58 | /// See also `CompletedMarker::precede`. | 61 | /// See also `CompletedMarker::precede`. |
59 | Start { | 62 | Start { |
diff --git a/crates/stdx/src/lib.rs b/crates/stdx/src/lib.rs index 1ff2559bb..73b121f8a 100644 --- a/crates/stdx/src/lib.rs +++ b/crates/stdx/src/lib.rs | |||
@@ -134,8 +134,10 @@ impl<'a> Iterator for LinesWithEnds<'a> { | |||
134 | 134 | ||
135 | /// Returns `idx` such that: | 135 | /// Returns `idx` such that: |
136 | /// | 136 | /// |
137 | /// ```text | ||
137 | /// ∀ x in slice[..idx]: pred(x) | 138 | /// ∀ x in slice[..idx]: pred(x) |
138 | /// && ∀ x in slice[idx..]: !pred(x) | 139 | /// && ∀ x in slice[idx..]: !pred(x) |
140 | /// ``` | ||
139 | /// | 141 | /// |
140 | /// https://github.com/rust-lang/rust/issues/73831 | 142 | /// https://github.com/rust-lang/rust/issues/73831 |
141 | pub fn partition_point<T, P>(slice: &[T], mut pred: P) -> usize | 143 | pub fn partition_point<T, P>(slice: &[T], mut pred: P) -> usize |