diff options
Diffstat (limited to 'crates/ide/src')
-rw-r--r-- | crates/ide/src/display/navigation_target.rs | 4 | ||||
-rw-r--r-- | crates/ide/src/display/short_label.rs | 10 | ||||
-rw-r--r-- | crates/ide/src/doc_links.rs | 23 | ||||
-rw-r--r-- | crates/ide/src/extend_selection.rs | 4 | ||||
-rw-r--r-- | crates/ide/src/goto_definition.rs | 90 | ||||
-rw-r--r-- | crates/ide/src/hover.rs | 30 | ||||
-rw-r--r-- | crates/ide/src/inlay_hints.rs | 2 | ||||
-rw-r--r-- | crates/ide/src/join_lines.rs | 2 | ||||
-rw-r--r-- | crates/ide/src/runnables.rs | 68 | ||||
-rw-r--r-- | crates/ide/src/status.rs | 2 | ||||
-rw-r--r-- | crates/ide/src/syntax_highlighting/format.rs | 2 | ||||
-rw-r--r-- | crates/ide/src/syntax_highlighting/inject.rs | 2 |
12 files changed, 144 insertions, 95 deletions
diff --git a/crates/ide/src/display/navigation_target.rs b/crates/ide/src/display/navigation_target.rs index 8d08e4763..16fa828ad 100644 --- a/crates/ide/src/display/navigation_target.rs +++ b/crates/ide/src/display/navigation_target.rs | |||
@@ -130,8 +130,7 @@ impl NavigationTarget { | |||
130 | node: InFile<&dyn ast::NameOwner>, | 130 | node: InFile<&dyn ast::NameOwner>, |
131 | kind: SymbolKind, | 131 | kind: SymbolKind, |
132 | ) -> NavigationTarget { | 132 | ) -> NavigationTarget { |
133 | let name = | 133 | let name = node.value.name().map(|it| it.text().into()).unwrap_or_else(|| "_".into()); |
134 | node.value.name().map(|it| it.text().clone()).unwrap_or_else(|| SmolStr::new("_")); | ||
135 | let focus_range = | 134 | let focus_range = |
136 | node.value.name().map(|it| node.with_value(it.syntax()).original_file_range(db).range); | 135 | node.value.name().map(|it| node.with_value(it.syntax()).original_file_range(db).range); |
137 | let frange = node.map(|it| it.syntax()).original_file_range(db); | 136 | let frange = node.map(|it| it.syntax()).original_file_range(db); |
@@ -272,6 +271,7 @@ impl ToNav for hir::Module { | |||
272 | ModuleSource::Module(node) => { | 271 | ModuleSource::Module(node) => { |
273 | (node.syntax(), node.name().map(|it| it.syntax().text_range())) | 272 | (node.syntax(), node.name().map(|it| it.syntax().text_range())) |
274 | } | 273 | } |
274 | ModuleSource::BlockExpr(node) => (node.syntax(), None), | ||
275 | }; | 275 | }; |
276 | let frange = src.with_value(syntax).original_file_range(db); | 276 | let frange = src.with_value(syntax).original_file_range(db); |
277 | NavigationTarget::from_syntax(frange.file_id, name, focus, frange.range, SymbolKind::Module) | 277 | NavigationTarget::from_syntax(frange.file_id, name, focus, frange.range, SymbolKind::Module) |
diff --git a/crates/ide/src/display/short_label.rs b/crates/ide/src/display/short_label.rs index 990f740b8..7ac050473 100644 --- a/crates/ide/src/display/short_label.rs +++ b/crates/ide/src/display/short_label.rs | |||
@@ -53,6 +53,12 @@ impl ShortLabel for ast::SourceFile { | |||
53 | } | 53 | } |
54 | } | 54 | } |
55 | 55 | ||
56 | impl ShortLabel for ast::BlockExpr { | ||
57 | fn short_label(&self) -> Option<String> { | ||
58 | None | ||
59 | } | ||
60 | } | ||
61 | |||
56 | impl ShortLabel for ast::TypeAlias { | 62 | impl ShortLabel for ast::TypeAlias { |
57 | fn short_label(&self) -> Option<String> { | 63 | fn short_label(&self) -> Option<String> { |
58 | short_label_from_node(self, "type ") | 64 | short_label_from_node(self, "type ") |
@@ -90,7 +96,7 @@ impl ShortLabel for ast::Variant { | |||
90 | impl ShortLabel for ast::ConstParam { | 96 | impl ShortLabel for ast::ConstParam { |
91 | fn short_label(&self) -> Option<String> { | 97 | fn short_label(&self) -> Option<String> { |
92 | let mut buf = "const ".to_owned(); | 98 | let mut buf = "const ".to_owned(); |
93 | buf.push_str(self.name()?.text().as_str()); | 99 | buf.push_str(self.name()?.text()); |
94 | if let Some(type_ref) = self.ty() { | 100 | if let Some(type_ref) = self.ty() { |
95 | format_to!(buf, ": {}", type_ref.syntax()); | 101 | format_to!(buf, ": {}", type_ref.syntax()); |
96 | } | 102 | } |
@@ -117,6 +123,6 @@ where | |||
117 | { | 123 | { |
118 | let mut buf = node.visibility().map(|v| format!("{} ", v.syntax())).unwrap_or_default(); | 124 | let mut buf = node.visibility().map(|v| format!("{} ", v.syntax())).unwrap_or_default(); |
119 | buf.push_str(label); | 125 | buf.push_str(label); |
120 | buf.push_str(node.name()?.text().as_str()); | 126 | buf.push_str(node.name()?.text()); |
121 | Some(buf) | 127 | Some(buf) |
122 | } | 128 | } |
diff --git a/crates/ide/src/doc_links.rs b/crates/ide/src/doc_links.rs index 1f08d7810..730e0dd0a 100644 --- a/crates/ide/src/doc_links.rs +++ b/crates/ide/src/doc_links.rs | |||
@@ -221,14 +221,31 @@ fn rewrite_intra_doc_link( | |||
221 | }?; | 221 | }?; |
222 | let krate = resolved.module(db)?.krate(); | 222 | let krate = resolved.module(db)?.krate(); |
223 | let canonical_path = resolved.canonical_path(db)?; | 223 | let canonical_path = resolved.canonical_path(db)?; |
224 | let new_target = get_doc_url(db, &krate)? | 224 | let mut new_url = get_doc_url(db, &krate)? |
225 | .join(&format!("{}/", krate.display_name(db)?)) | 225 | .join(&format!("{}/", krate.display_name(db)?)) |
226 | .ok()? | 226 | .ok()? |
227 | .join(&canonical_path.replace("::", "/")) | 227 | .join(&canonical_path.replace("::", "/")) |
228 | .ok()? | 228 | .ok()? |
229 | .join(&get_symbol_filename(db, &resolved)?) | 229 | .join(&get_symbol_filename(db, &resolved)?) |
230 | .ok()? | 230 | .ok()?; |
231 | .into_string(); | 231 | |
232 | if let ModuleDef::Trait(t) = resolved { | ||
233 | let items = t.items(db); | ||
234 | if let Some(field_or_assoc_item) = items.iter().find_map(|assoc_item| { | ||
235 | if let Some(name) = assoc_item.name(db) { | ||
236 | if link.to_string() == format!("{}::{}", canonical_path, name) { | ||
237 | return Some(FieldOrAssocItem::AssocItem(*assoc_item)); | ||
238 | } | ||
239 | } | ||
240 | None | ||
241 | }) { | ||
242 | if let Some(fragment) = get_symbol_fragment(db, &field_or_assoc_item) { | ||
243 | new_url = new_url.join(&fragment).ok()?; | ||
244 | } | ||
245 | }; | ||
246 | } | ||
247 | |||
248 | let new_target = new_url.into_string(); | ||
232 | let new_title = strip_prefixes_suffixes(title); | 249 | let new_title = strip_prefixes_suffixes(title); |
233 | Some((new_target, new_title.to_string())) | 250 | Some((new_target, new_title.to_string())) |
234 | } | 251 | } |
diff --git a/crates/ide/src/extend_selection.rs b/crates/ide/src/extend_selection.rs index 17a540972..2d722dee0 100644 --- a/crates/ide/src/extend_selection.rs +++ b/crates/ide/src/extend_selection.rs | |||
@@ -213,8 +213,8 @@ fn extend_ws(root: &SyntaxNode, ws: SyntaxToken, offset: TextSize) -> TextRange | |||
213 | let ws_text = ws.text(); | 213 | let ws_text = ws.text(); |
214 | let suffix = TextRange::new(offset, ws.text_range().end()) - ws.text_range().start(); | 214 | let suffix = TextRange::new(offset, ws.text_range().end()) - ws.text_range().start(); |
215 | let prefix = TextRange::new(ws.text_range().start(), offset) - ws.text_range().start(); | 215 | let prefix = TextRange::new(ws.text_range().start(), offset) - ws.text_range().start(); |
216 | let ws_suffix = &ws_text.as_str()[suffix]; | 216 | let ws_suffix = &ws_text[suffix]; |
217 | let ws_prefix = &ws_text.as_str()[prefix]; | 217 | let ws_prefix = &ws_text[prefix]; |
218 | if ws_text.contains('\n') && !ws_suffix.contains('\n') { | 218 | if ws_text.contains('\n') && !ws_suffix.contains('\n') { |
219 | if let Some(node) = ws.next_sibling_or_token() { | 219 | if let Some(node) = ws.next_sibling_or_token() { |
220 | let start = match ws_prefix.rfind('\n') { | 220 | let start = match ws_prefix.rfind('\n') { |
diff --git a/crates/ide/src/goto_definition.rs b/crates/ide/src/goto_definition.rs index a1d2bce1d..1a997fa40 100644 --- a/crates/ide/src/goto_definition.rs +++ b/crates/ide/src/goto_definition.rs | |||
@@ -2,16 +2,14 @@ use either::Either; | |||
2 | use hir::{HasAttrs, ModuleDef, Semantics}; | 2 | use hir::{HasAttrs, ModuleDef, Semantics}; |
3 | use ide_db::{ | 3 | use ide_db::{ |
4 | defs::{Definition, NameClass, NameRefClass}, | 4 | defs::{Definition, NameClass, NameRefClass}, |
5 | symbol_index, RootDatabase, | 5 | RootDatabase, |
6 | }; | 6 | }; |
7 | use syntax::{ | 7 | use syntax::{ |
8 | ast, match_ast, AstNode, AstToken, SyntaxKind::*, SyntaxToken, TextSize, TokenAtOffset, T, | 8 | ast, match_ast, AstNode, AstToken, SyntaxKind::*, SyntaxToken, TextSize, TokenAtOffset, T, |
9 | }; | 9 | }; |
10 | 10 | ||
11 | use crate::{ | 11 | use crate::{ |
12 | display::{ToNav, TryToNav}, | 12 | display::TryToNav, doc_links::extract_definitions_from_markdown, runnables::doc_owner_to_def, |
13 | doc_links::extract_definitions_from_markdown, | ||
14 | runnables::doc_owner_to_def, | ||
15 | FilePosition, NavigationTarget, RangeInfo, | 13 | FilePosition, NavigationTarget, RangeInfo, |
16 | }; | 14 | }; |
17 | 15 | ||
@@ -38,28 +36,26 @@ pub(crate) fn goto_definition( | |||
38 | return Some(RangeInfo::new(original_token.text_range(), vec![nav])); | 36 | return Some(RangeInfo::new(original_token.text_range(), vec![nav])); |
39 | } | 37 | } |
40 | 38 | ||
41 | let nav_targets = match_ast! { | 39 | let nav = match_ast! { |
42 | match parent { | 40 | match parent { |
43 | ast::NameRef(name_ref) => { | 41 | ast::NameRef(name_ref) => { |
44 | reference_definition(&sema, Either::Right(&name_ref)).to_vec() | 42 | reference_definition(&sema, Either::Right(&name_ref)) |
45 | }, | 43 | }, |
46 | ast::Name(name) => { | 44 | ast::Name(name) => { |
47 | let def = NameClass::classify(&sema, &name)?.referenced_or_defined(sema.db); | 45 | let def = NameClass::classify(&sema, &name)?.referenced_or_defined(sema.db); |
48 | let nav = def.try_to_nav(sema.db)?; | 46 | def.try_to_nav(sema.db) |
49 | vec![nav] | ||
50 | }, | 47 | }, |
51 | ast::Lifetime(lt) => if let Some(name_class) = NameClass::classify_lifetime(&sema, <) { | 48 | ast::Lifetime(lt) => if let Some(name_class) = NameClass::classify_lifetime(&sema, <) { |
52 | let def = name_class.referenced_or_defined(sema.db); | 49 | let def = name_class.referenced_or_defined(sema.db); |
53 | let nav = def.try_to_nav(sema.db)?; | 50 | def.try_to_nav(sema.db) |
54 | vec![nav] | ||
55 | } else { | 51 | } else { |
56 | reference_definition(&sema, Either::Left(<)).to_vec() | 52 | reference_definition(&sema, Either::Left(<)) |
57 | }, | 53 | }, |
58 | _ => return None, | 54 | _ => return None, |
59 | } | 55 | } |
60 | }; | 56 | }; |
61 | 57 | ||
62 | Some(RangeInfo::new(original_token.text_range(), nav_targets)) | 58 | Some(RangeInfo::new(original_token.text_range(), nav.into_iter().collect())) |
63 | } | 59 | } |
64 | 60 | ||
65 | fn def_for_doc_comment( | 61 | fn def_for_doc_comment( |
@@ -120,42 +116,16 @@ fn pick_best(tokens: TokenAtOffset<SyntaxToken>) -> Option<SyntaxToken> { | |||
120 | } | 116 | } |
121 | } | 117 | } |
122 | 118 | ||
123 | #[derive(Debug)] | ||
124 | pub(crate) enum ReferenceResult { | ||
125 | Exact(NavigationTarget), | ||
126 | Approximate(Vec<NavigationTarget>), | ||
127 | } | ||
128 | |||
129 | impl ReferenceResult { | ||
130 | fn to_vec(self) -> Vec<NavigationTarget> { | ||
131 | match self { | ||
132 | ReferenceResult::Exact(target) => vec![target], | ||
133 | ReferenceResult::Approximate(vec) => vec, | ||
134 | } | ||
135 | } | ||
136 | } | ||
137 | |||
138 | pub(crate) fn reference_definition( | 119 | pub(crate) fn reference_definition( |
139 | sema: &Semantics<RootDatabase>, | 120 | sema: &Semantics<RootDatabase>, |
140 | name_ref: Either<&ast::Lifetime, &ast::NameRef>, | 121 | name_ref: Either<&ast::Lifetime, &ast::NameRef>, |
141 | ) -> ReferenceResult { | 122 | ) -> Option<NavigationTarget> { |
142 | let name_kind = name_ref.either( | 123 | let name_kind = name_ref.either( |
143 | |lifetime| NameRefClass::classify_lifetime(sema, lifetime), | 124 | |lifetime| NameRefClass::classify_lifetime(sema, lifetime), |
144 | |name_ref| NameRefClass::classify(sema, name_ref), | 125 | |name_ref| NameRefClass::classify(sema, name_ref), |
145 | ); | 126 | )?; |
146 | if let Some(def) = name_kind { | 127 | let def = name_kind.referenced(sema.db); |
147 | let def = def.referenced(sema.db); | 128 | def.try_to_nav(sema.db) |
148 | return match def.try_to_nav(sema.db) { | ||
149 | Some(nav) => ReferenceResult::Exact(nav), | ||
150 | None => ReferenceResult::Approximate(Vec::new()), | ||
151 | }; | ||
152 | } | ||
153 | |||
154 | // Fallback index based approach: | ||
155 | let name = name_ref.either(ast::Lifetime::text, ast::NameRef::text); | ||
156 | let navs = | ||
157 | symbol_index::index_resolve(sema.db, name).into_iter().map(|s| s.to_nav(sema.db)).collect(); | ||
158 | ReferenceResult::Approximate(navs) | ||
159 | } | 129 | } |
160 | 130 | ||
161 | #[cfg(test)] | 131 | #[cfg(test)] |
@@ -192,12 +162,12 @@ mod tests { | |||
192 | fn goto_def_for_extern_crate() { | 162 | fn goto_def_for_extern_crate() { |
193 | check( | 163 | check( |
194 | r#" | 164 | r#" |
195 | //- /main.rs crate:main deps:std | 165 | //- /main.rs crate:main deps:std |
196 | extern crate std$0; | 166 | extern crate std$0; |
197 | //- /std/lib.rs crate:std | 167 | //- /std/lib.rs crate:std |
198 | // empty | 168 | // empty |
199 | //^ file | 169 | //^ file |
200 | "#, | 170 | "#, |
201 | ) | 171 | ) |
202 | } | 172 | } |
203 | 173 | ||
@@ -205,12 +175,12 @@ mod tests { | |||
205 | fn goto_def_for_renamed_extern_crate() { | 175 | fn goto_def_for_renamed_extern_crate() { |
206 | check( | 176 | check( |
207 | r#" | 177 | r#" |
208 | //- /main.rs crate:main deps:std | 178 | //- /main.rs crate:main deps:std |
209 | extern crate std as abc$0; | 179 | extern crate std as abc$0; |
210 | //- /std/lib.rs crate:std | 180 | //- /std/lib.rs crate:std |
211 | // empty | 181 | // empty |
212 | //^ file | 182 | //^ file |
213 | "#, | 183 | "#, |
214 | ) | 184 | ) |
215 | } | 185 | } |
216 | 186 | ||
@@ -297,13 +267,13 @@ fn bar() { | |||
297 | fn goto_def_for_macros_from_other_crates() { | 267 | fn goto_def_for_macros_from_other_crates() { |
298 | check( | 268 | check( |
299 | r#" | 269 | r#" |
300 | //- /lib.rs | 270 | //- /lib.rs crate:main deps:foo |
301 | use foo::foo; | 271 | use foo::foo; |
302 | fn bar() { | 272 | fn bar() { |
303 | $0foo!(); | 273 | $0foo!(); |
304 | } | 274 | } |
305 | 275 | ||
306 | //- /foo/lib.rs | 276 | //- /foo/lib.rs crate:foo |
307 | #[macro_export] | 277 | #[macro_export] |
308 | macro_rules! foo { () => { () } } | 278 | macro_rules! foo { () => { () } } |
309 | //^^^ | 279 | //^^^ |
@@ -315,10 +285,10 @@ macro_rules! foo { () => { () } } | |||
315 | fn goto_def_for_macros_in_use_tree() { | 285 | fn goto_def_for_macros_in_use_tree() { |
316 | check( | 286 | check( |
317 | r#" | 287 | r#" |
318 | //- /lib.rs | 288 | //- /lib.rs crate:main deps:foo |
319 | use foo::foo$0; | 289 | use foo::foo$0; |
320 | 290 | ||
321 | //- /foo/lib.rs | 291 | //- /foo/lib.rs crate:foo |
322 | #[macro_export] | 292 | #[macro_export] |
323 | macro_rules! foo { () => { () } } | 293 | macro_rules! foo { () => { () } } |
324 | //^^^ | 294 | //^^^ |
@@ -976,10 +946,10 @@ type Alias<T> = T$0; | |||
976 | fn goto_def_for_macro_container() { | 946 | fn goto_def_for_macro_container() { |
977 | check( | 947 | check( |
978 | r#" | 948 | r#" |
979 | //- /lib.rs | 949 | //- /lib.rs crate:main deps:foo |
980 | foo::module$0::mac!(); | 950 | foo::module$0::mac!(); |
981 | 951 | ||
982 | //- /foo/lib.rs | 952 | //- /foo/lib.rs crate:foo |
983 | pub mod module { | 953 | pub mod module { |
984 | //^^^^^^ | 954 | //^^^^^^ |
985 | #[macro_export] | 955 | #[macro_export] |
diff --git a/crates/ide/src/hover.rs b/crates/ide/src/hover.rs index 44ebdbd35..d47a4cb0f 100644 --- a/crates/ide/src/hover.rs +++ b/crates/ide/src/hover.rs | |||
@@ -321,6 +321,7 @@ fn hover_for_definition(db: &RootDatabase, def: Definition) -> Option<Markup> { | |||
321 | match it.definition_source(db).value { | 321 | match it.definition_source(db).value { |
322 | ModuleSource::Module(it) => it.short_label(), | 322 | ModuleSource::Module(it) => it.short_label(), |
323 | ModuleSource::SourceFile(it) => it.short_label(), | 323 | ModuleSource::SourceFile(it) => it.short_label(), |
324 | ModuleSource::BlockExpr(it) => it.short_label(), | ||
324 | }, | 325 | }, |
325 | mod_path, | 326 | mod_path, |
326 | ), | 327 | ), |
@@ -1825,6 +1826,35 @@ pub struct B$0ar | |||
1825 | "#]], | 1826 | "#]], |
1826 | ); | 1827 | ); |
1827 | } | 1828 | } |
1829 | #[test] | ||
1830 | fn test_hover_intra_link_reference_to_trait_method() { | ||
1831 | check( | ||
1832 | r#" | ||
1833 | pub trait Foo { | ||
1834 | fn buzz() -> usize; | ||
1835 | } | ||
1836 | /// [Foo][buzz] | ||
1837 | /// | ||
1838 | /// [buzz]: Foo::buzz | ||
1839 | pub struct B$0ar | ||
1840 | "#, | ||
1841 | expect![[r#" | ||
1842 | *Bar* | ||
1843 | |||
1844 | ```rust | ||
1845 | test | ||
1846 | ``` | ||
1847 | |||
1848 | ```rust | ||
1849 | pub struct Bar | ||
1850 | ``` | ||
1851 | |||
1852 | --- | ||
1853 | |||
1854 | [Foo](https://docs.rs/test/*/test/trait.Foo.html#tymethod.buzz) | ||
1855 | "#]], | ||
1856 | ); | ||
1857 | } | ||
1828 | 1858 | ||
1829 | #[test] | 1859 | #[test] |
1830 | fn test_hover_external_url() { | 1860 | fn test_hover_external_url() { |
diff --git a/crates/ide/src/inlay_hints.rs b/crates/ide/src/inlay_hints.rs index a2039fcc7..54485fd30 100644 --- a/crates/ide/src/inlay_hints.rs +++ b/crates/ide/src/inlay_hints.rs | |||
@@ -411,7 +411,7 @@ fn get_string_representation(expr: &ast::Expr) -> Option<String> { | |||
411 | match expr { | 411 | match expr { |
412 | ast::Expr::MethodCallExpr(method_call_expr) => { | 412 | ast::Expr::MethodCallExpr(method_call_expr) => { |
413 | let name_ref = method_call_expr.name_ref()?; | 413 | let name_ref = method_call_expr.name_ref()?; |
414 | match name_ref.text().as_str() { | 414 | match name_ref.text() { |
415 | "clone" => method_call_expr.receiver().map(|rec| rec.to_string()), | 415 | "clone" => method_call_expr.receiver().map(|rec| rec.to_string()), |
416 | name_ref => Some(name_ref.to_owned()), | 416 | name_ref => Some(name_ref.to_owned()), |
417 | } | 417 | } |
diff --git a/crates/ide/src/join_lines.rs b/crates/ide/src/join_lines.rs index 981467c8d..631bde0f1 100644 --- a/crates/ide/src/join_lines.rs +++ b/crates/ide/src/join_lines.rs | |||
@@ -59,7 +59,7 @@ fn remove_newline(edit: &mut TextEditBuilder, token: &SyntaxToken, offset: TextS | |||
59 | // The node is either the first or the last in the file | 59 | // The node is either the first or the last in the file |
60 | let suff = &token.text()[TextRange::new( | 60 | let suff = &token.text()[TextRange::new( |
61 | offset - token.text_range().start() + TextSize::of('\n'), | 61 | offset - token.text_range().start() + TextSize::of('\n'), |
62 | TextSize::of(token.text().as_str()), | 62 | TextSize::of(token.text()), |
63 | )]; | 63 | )]; |
64 | let spaces = suff.bytes().take_while(|&b| b == b' ').count(); | 64 | let spaces = suff.bytes().take_while(|&b| b == b' ').count(); |
65 | 65 | ||
diff --git a/crates/ide/src/runnables.rs b/crates/ide/src/runnables.rs index e282b31af..33170906d 100644 --- a/crates/ide/src/runnables.rs +++ b/crates/ide/src/runnables.rs | |||
@@ -9,6 +9,7 @@ use syntax::{ | |||
9 | ast::{self, AstNode, AttrsOwner}, | 9 | ast::{self, AstNode, AttrsOwner}, |
10 | match_ast, SyntaxNode, | 10 | match_ast, SyntaxNode, |
11 | }; | 11 | }; |
12 | use test_utils::mark; | ||
12 | 13 | ||
13 | use crate::{ | 14 | use crate::{ |
14 | display::{ToNav, TryToNav}, | 15 | display::{ToNav, TryToNav}, |
@@ -96,28 +97,26 @@ impl Runnable { | |||
96 | pub(crate) fn runnables(db: &RootDatabase, file_id: FileId) -> Vec<Runnable> { | 97 | pub(crate) fn runnables(db: &RootDatabase, file_id: FileId) -> Vec<Runnable> { |
97 | let sema = Semantics::new(db); | 98 | let sema = Semantics::new(db); |
98 | let module = match sema.to_module_def(file_id) { | 99 | let module = match sema.to_module_def(file_id) { |
99 | None => return vec![], | 100 | None => return Vec::new(), |
100 | Some(it) => it, | 101 | Some(it) => it, |
101 | }; | 102 | }; |
102 | 103 | ||
103 | runnables_mod(&sema, module) | 104 | let mut res = Vec::new(); |
105 | runnables_mod(&sema, &mut res, module); | ||
106 | res | ||
104 | } | 107 | } |
105 | 108 | ||
106 | fn runnables_mod(sema: &Semantics<RootDatabase>, module: hir::Module) -> Vec<Runnable> { | 109 | fn runnables_mod(sema: &Semantics<RootDatabase>, acc: &mut Vec<Runnable>, module: hir::Module) { |
107 | let mut res: Vec<Runnable> = module | 110 | acc.extend(module.declarations(sema.db).into_iter().filter_map(|def| { |
108 | .declarations(sema.db) | 111 | let runnable = match def { |
109 | .into_iter() | 112 | hir::ModuleDef::Module(it) => runnable_mod(&sema, it), |
110 | .filter_map(|def| { | 113 | hir::ModuleDef::Function(it) => runnable_fn(&sema, it), |
111 | let runnable = match def { | 114 | _ => None, |
112 | hir::ModuleDef::Module(it) => runnable_mod(&sema, it), | 115 | }; |
113 | hir::ModuleDef::Function(it) => runnable_fn(&sema, it), | 116 | runnable.or_else(|| module_def_doctest(&sema, def)) |
114 | _ => None, | 117 | })); |
115 | }; | ||
116 | runnable.or_else(|| module_def_doctest(&sema, def)) | ||
117 | }) | ||
118 | .collect(); | ||
119 | 118 | ||
120 | res.extend(module.impl_defs(sema.db).into_iter().flat_map(|it| it.items(sema.db)).filter_map( | 119 | acc.extend(module.impl_defs(sema.db).into_iter().flat_map(|it| it.items(sema.db)).filter_map( |
121 | |def| match def { | 120 | |def| match def { |
122 | hir::AssocItem::Function(it) => { | 121 | hir::AssocItem::Function(it) => { |
123 | runnable_fn(&sema, it).or_else(|| module_def_doctest(&sema, it.into())) | 122 | runnable_fn(&sema, it).or_else(|| module_def_doctest(&sema, it.into())) |
@@ -127,12 +126,15 @@ fn runnables_mod(sema: &Semantics<RootDatabase>, module: hir::Module) -> Vec<Run | |||
127 | }, | 126 | }, |
128 | )); | 127 | )); |
129 | 128 | ||
130 | res.extend(module.declarations(sema.db).into_iter().flat_map(|def| match def { | 129 | for def in module.declarations(sema.db) { |
131 | hir::ModuleDef::Module(it) => runnables_mod(sema, it), | 130 | if let hir::ModuleDef::Module(submodule) = def { |
132 | _ => vec![], | 131 | match submodule.definition_source(sema.db).value { |
133 | })); | 132 | hir::ModuleSource::Module(_) => runnables_mod(sema, acc, submodule), |
134 | 133 | hir::ModuleSource::SourceFile(_) => mark::hit!(dont_recurse_in_outline_submodules), | |
135 | res | 134 | hir::ModuleSource::BlockExpr(_) => {} // inner items aren't runnable |
135 | } | ||
136 | } | ||
137 | } | ||
136 | } | 138 | } |
137 | 139 | ||
138 | pub(crate) fn runnable_fn(sema: &Semantics<RootDatabase>, def: hir::Function) -> Option<Runnable> { | 140 | pub(crate) fn runnable_fn(sema: &Semantics<RootDatabase>, def: hir::Function) -> Option<Runnable> { |
@@ -326,6 +328,7 @@ fn has_test_function_or_multiple_test_submodules( | |||
326 | #[cfg(test)] | 328 | #[cfg(test)] |
327 | mod tests { | 329 | mod tests { |
328 | use expect_test::{expect, Expect}; | 330 | use expect_test::{expect, Expect}; |
331 | use test_utils::mark; | ||
329 | 332 | ||
330 | use crate::fixture; | 333 | use crate::fixture; |
331 | 334 | ||
@@ -1050,4 +1053,25 @@ mod tests { | |||
1050 | "#]], | 1053 | "#]], |
1051 | ); | 1054 | ); |
1052 | } | 1055 | } |
1056 | |||
1057 | #[test] | ||
1058 | fn dont_recurse_in_outline_submodules() { | ||
1059 | mark::check!(dont_recurse_in_outline_submodules); | ||
1060 | check( | ||
1061 | r#" | ||
1062 | //- /lib.rs | ||
1063 | $0 | ||
1064 | mod m; | ||
1065 | //- /m.rs | ||
1066 | mod tests { | ||
1067 | #[test] | ||
1068 | fn t() {} | ||
1069 | } | ||
1070 | "#, | ||
1071 | &[], | ||
1072 | expect![[r#" | ||
1073 | [] | ||
1074 | "#]], | ||
1075 | ); | ||
1076 | } | ||
1053 | } | 1077 | } |
diff --git a/crates/ide/src/status.rs b/crates/ide/src/status.rs index e10d7c3a4..137c38c0d 100644 --- a/crates/ide/src/status.rs +++ b/crates/ide/src/status.rs | |||
@@ -38,6 +38,7 @@ pub(crate) fn status(db: &RootDatabase, file_id: Option<FileId>) -> String { | |||
38 | format_to!(buf, "{}\n", syntax_tree_stats(db)); | 38 | format_to!(buf, "{}\n", syntax_tree_stats(db)); |
39 | format_to!(buf, "{} (macros)\n", macro_syntax_tree_stats(db)); | 39 | format_to!(buf, "{} (macros)\n", macro_syntax_tree_stats(db)); |
40 | format_to!(buf, "{} total\n", memory_usage()); | 40 | format_to!(buf, "{} total\n", memory_usage()); |
41 | format_to!(buf, "\ncounts:\n{}", profile::countme::get_all()); | ||
41 | 42 | ||
42 | if let Some(file_id) = file_id { | 43 | if let Some(file_id) = file_id { |
43 | format_to!(buf, "\nfile info:\n"); | 44 | format_to!(buf, "\nfile info:\n"); |
@@ -60,6 +61,7 @@ pub(crate) fn status(db: &RootDatabase, file_id: Option<FileId>) -> String { | |||
60 | None => format_to!(buf, "does not belong to any crate"), | 61 | None => format_to!(buf, "does not belong to any crate"), |
61 | } | 62 | } |
62 | } | 63 | } |
64 | |||
63 | buf | 65 | buf |
64 | } | 66 | } |
65 | 67 | ||
diff --git a/crates/ide/src/syntax_highlighting/format.rs b/crates/ide/src/syntax_highlighting/format.rs index 63bff6376..8c67a0863 100644 --- a/crates/ide/src/syntax_highlighting/format.rs +++ b/crates/ide/src/syntax_highlighting/format.rs | |||
@@ -31,7 +31,7 @@ fn is_format_string(string: &ast::String) -> Option<()> { | |||
31 | let parent = string.syntax().parent(); | 31 | let parent = string.syntax().parent(); |
32 | 32 | ||
33 | let name = parent.parent().and_then(ast::MacroCall::cast)?.path()?.segment()?.name_ref()?; | 33 | let name = parent.parent().and_then(ast::MacroCall::cast)?.path()?.segment()?.name_ref()?; |
34 | if !matches!(name.text().as_str(), "format_args" | "format_args_nl") { | 34 | if !matches!(name.text(), "format_args" | "format_args_nl") { |
35 | return None; | 35 | return None; |
36 | } | 36 | } |
37 | 37 | ||
diff --git a/crates/ide/src/syntax_highlighting/inject.rs b/crates/ide/src/syntax_highlighting/inject.rs index 281461493..8cdc3688f 100644 --- a/crates/ide/src/syntax_highlighting/inject.rs +++ b/crates/ide/src/syntax_highlighting/inject.rs | |||
@@ -116,7 +116,7 @@ pub(super) fn doc_comment(hl: &mut Highlights, node: &SyntaxNode) { | |||
116 | None => (), | 116 | None => (), |
117 | } | 117 | } |
118 | 118 | ||
119 | let line: &str = comment.text().as_str(); | 119 | let line: &str = comment.text(); |
120 | let range = comment.syntax().text_range(); | 120 | let range = comment.syntax().text_range(); |
121 | 121 | ||
122 | let mut pos = TextSize::of(comment.prefix()); | 122 | let mut pos = TextSize::of(comment.prefix()); |