diff options
Diffstat (limited to 'crates/ide')
-rw-r--r-- | crates/ide/src/call_hierarchy.rs | 11 | ||||
-rw-r--r-- | crates/ide/src/display.rs | 1 | ||||
-rw-r--r-- | crates/ide/src/display/navigation_target.rs | 14 | ||||
-rw-r--r-- | crates/ide/src/doc_links.rs | 2 | ||||
-rw-r--r-- | crates/ide/src/extend_selection.rs | 13 | ||||
-rw-r--r-- | crates/ide/src/goto_definition.rs | 4 | ||||
-rw-r--r-- | crates/ide/src/goto_type_definition.rs | 2 | ||||
-rw-r--r-- | crates/ide/src/hover.rs | 186 | ||||
-rw-r--r-- | crates/ide/src/join_lines.rs | 44 | ||||
-rw-r--r-- | crates/ide/src/matching_brace.rs | 2 | ||||
-rw-r--r-- | crates/ide/src/parent_module.rs | 79 | ||||
-rw-r--r-- | crates/ide/src/references.rs | 7 | ||||
-rw-r--r-- | crates/ide/src/runnables.rs | 3 | ||||
-rw-r--r-- | crates/ide/src/syntax_highlighting.rs | 19 | ||||
-rw-r--r-- | crates/ide/src/syntax_highlighting/format.rs | 2 | ||||
-rw-r--r-- | crates/ide/src/syntax_tree.rs | 2 | ||||
-rw-r--r-- | crates/ide/src/typing.rs | 2 |
17 files changed, 243 insertions, 150 deletions
diff --git a/crates/ide/src/call_hierarchy.rs b/crates/ide/src/call_hierarchy.rs index b848945d7..96021f677 100644 --- a/crates/ide/src/call_hierarchy.rs +++ b/crates/ide/src/call_hierarchy.rs | |||
@@ -53,10 +53,8 @@ pub(crate) fn incoming_calls(db: &RootDatabase, position: FilePosition) -> Optio | |||
53 | for (r_range, _) in references { | 53 | for (r_range, _) in references { |
54 | let token = file.token_at_offset(r_range.start()).next()?; | 54 | let token = file.token_at_offset(r_range.start()).next()?; |
55 | let token = sema.descend_into_macros(token); | 55 | let token = sema.descend_into_macros(token); |
56 | let syntax = token.parent(); | ||
57 | |||
58 | // This target is the containing function | 56 | // This target is the containing function |
59 | if let Some(nav) = syntax.ancestors().find_map(|node| { | 57 | if let Some(nav) = token.ancestors().find_map(|node| { |
60 | let fn_ = ast::Fn::cast(node)?; | 58 | let fn_ = ast::Fn::cast(node)?; |
61 | let def = sema.to_def(&fn_)?; | 59 | let def = sema.to_def(&fn_)?; |
62 | def.try_to_nav(sema.db) | 60 | def.try_to_nav(sema.db) |
@@ -77,12 +75,13 @@ pub(crate) fn outgoing_calls(db: &RootDatabase, position: FilePosition) -> Optio | |||
77 | let file = file.syntax(); | 75 | let file = file.syntax(); |
78 | let token = file.token_at_offset(position.offset).next()?; | 76 | let token = file.token_at_offset(position.offset).next()?; |
79 | let token = sema.descend_into_macros(token); | 77 | let token = sema.descend_into_macros(token); |
80 | let syntax = token.parent(); | ||
81 | 78 | ||
82 | let mut calls = CallLocations::default(); | 79 | let mut calls = CallLocations::default(); |
83 | 80 | ||
84 | syntax | 81 | token |
85 | .descendants() | 82 | .parent() |
83 | .into_iter() | ||
84 | .flat_map(|it| it.descendants()) | ||
86 | .filter_map(|node| FnCallNode::with_node_exact(&node)) | 85 | .filter_map(|node| FnCallNode::with_node_exact(&node)) |
87 | .filter_map(|call_node| { | 86 | .filter_map(|call_node| { |
88 | let name_ref = call_node.name_ref()?; | 87 | let name_ref = call_node.name_ref()?; |
diff --git a/crates/ide/src/display.rs b/crates/ide/src/display.rs index bae9e40df..1f7b665c0 100644 --- a/crates/ide/src/display.rs +++ b/crates/ide/src/display.rs | |||
@@ -5,6 +5,5 @@ pub(crate) mod navigation_target; | |||
5 | mod short_label; | 5 | mod short_label; |
6 | 6 | ||
7 | pub(crate) use navigation_target::{ToNav, TryToNav}; | 7 | pub(crate) use navigation_target::{ToNav, TryToNav}; |
8 | pub(crate) use short_label::ShortLabel; | ||
9 | 8 | ||
10 | pub(crate) use syntax::display::{function_declaration, macro_label}; | 9 | pub(crate) use syntax::display::{function_declaration, macro_label}; |
diff --git a/crates/ide/src/display/navigation_target.rs b/crates/ide/src/display/navigation_target.rs index 198243466..69c3751a1 100644 --- a/crates/ide/src/display/navigation_target.rs +++ b/crates/ide/src/display/navigation_target.rs | |||
@@ -3,7 +3,9 @@ | |||
3 | use std::fmt; | 3 | use std::fmt; |
4 | 4 | ||
5 | use either::Either; | 5 | use either::Either; |
6 | use hir::{AssocItem, Documentation, FieldSource, HasAttrs, HasSource, InFile, ModuleSource}; | 6 | use hir::{ |
7 | AssocItem, Documentation, FieldSource, HasAttrs, HasSource, HirDisplay, InFile, ModuleSource, | ||
8 | }; | ||
7 | use ide_db::{ | 9 | use ide_db::{ |
8 | base_db::{FileId, FileRange, SourceDatabase}, | 10 | base_db::{FileId, FileRange, SourceDatabase}, |
9 | symbol_index::FileSymbolKind, | 11 | symbol_index::FileSymbolKind, |
@@ -98,7 +100,7 @@ impl NavigationTarget { | |||
98 | SymbolKind::Module, | 100 | SymbolKind::Module, |
99 | ); | 101 | ); |
100 | res.docs = module.attrs(db).docs(); | 102 | res.docs = module.attrs(db).docs(); |
101 | res.description = src.value.short_label(); | 103 | res.description = Some(module.display(db).to_string()); |
102 | return res; | 104 | return res; |
103 | } | 105 | } |
104 | module.to_nav(db) | 106 | module.to_nav(db) |
@@ -251,8 +253,8 @@ impl ToNavFromAst for hir::Trait { | |||
251 | 253 | ||
252 | impl<D> TryToNav for D | 254 | impl<D> TryToNav for D |
253 | where | 255 | where |
254 | D: HasSource + ToNavFromAst + Copy + HasAttrs, | 256 | D: HasSource + ToNavFromAst + Copy + HasAttrs + HirDisplay, |
255 | D::Ast: ast::NameOwner + ShortLabel, | 257 | D::Ast: ast::NameOwner, |
256 | { | 258 | { |
257 | fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> { | 259 | fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> { |
258 | let src = self.source(db)?; | 260 | let src = self.source(db)?; |
@@ -262,7 +264,7 @@ where | |||
262 | D::KIND, | 264 | D::KIND, |
263 | ); | 265 | ); |
264 | res.docs = self.docs(db); | 266 | res.docs = self.docs(db); |
265 | res.description = src.value.short_label(); | 267 | res.description = Some(self.display(db).to_string()); |
266 | Some(res) | 268 | Some(res) |
267 | } | 269 | } |
268 | } | 270 | } |
@@ -317,7 +319,7 @@ impl TryToNav for hir::Field { | |||
317 | let mut res = | 319 | let mut res = |
318 | NavigationTarget::from_named(db, src.with_value(it), SymbolKind::Field); | 320 | NavigationTarget::from_named(db, src.with_value(it), SymbolKind::Field); |
319 | res.docs = self.docs(db); | 321 | res.docs = self.docs(db); |
320 | res.description = it.short_label(); | 322 | res.description = Some(self.display(db).to_string()); |
321 | res | 323 | res |
322 | } | 324 | } |
323 | FieldSource::Pos(it) => { | 325 | FieldSource::Pos(it) => { |
diff --git a/crates/ide/src/doc_links.rs b/crates/ide/src/doc_links.rs index 7bdd3cca3..461e11060 100644 --- a/crates/ide/src/doc_links.rs +++ b/crates/ide/src/doc_links.rs | |||
@@ -279,7 +279,7 @@ pub(crate) fn external_docs( | |||
279 | let token = pick_best(file.token_at_offset(position.offset))?; | 279 | let token = pick_best(file.token_at_offset(position.offset))?; |
280 | let token = sema.descend_into_macros(token); | 280 | let token = sema.descend_into_macros(token); |
281 | 281 | ||
282 | let node = token.parent(); | 282 | let node = token.parent()?; |
283 | let definition = match_ast! { | 283 | let definition = match_ast! { |
284 | match node { | 284 | match node { |
285 | ast::NameRef(name_ref) => NameRefClass::classify(&sema, &name_ref).map(|d| d.referenced(sema.db)), | 285 | ast::NameRef(name_ref) => NameRefClass::classify(&sema, &name_ref).map(|d| d.referenced(sema.db)), |
diff --git a/crates/ide/src/extend_selection.rs b/crates/ide/src/extend_selection.rs index b540d04fe..e187243cb 100644 --- a/crates/ide/src/extend_selection.rs +++ b/crates/ide/src/extend_selection.rs | |||
@@ -88,7 +88,7 @@ fn try_extend_selection( | |||
88 | return Some(range); | 88 | return Some(range); |
89 | } | 89 | } |
90 | } | 90 | } |
91 | token.parent() | 91 | token.parent()? |
92 | } | 92 | } |
93 | NodeOrToken::Node(node) => node, | 93 | NodeOrToken::Node(node) => node, |
94 | }; | 94 | }; |
@@ -142,7 +142,8 @@ fn extend_tokens_from_range( | |||
142 | let extended = { | 142 | let extended = { |
143 | let fst_expanded = sema.descend_into_macros(first_token.clone()); | 143 | let fst_expanded = sema.descend_into_macros(first_token.clone()); |
144 | let lst_expanded = sema.descend_into_macros(last_token.clone()); | 144 | let lst_expanded = sema.descend_into_macros(last_token.clone()); |
145 | let mut lca = algo::least_common_ancestor(&fst_expanded.parent(), &lst_expanded.parent())?; | 145 | let mut lca = |
146 | algo::least_common_ancestor(&fst_expanded.parent()?, &lst_expanded.parent()?)?; | ||
146 | lca = shallowest_node(&lca); | 147 | lca = shallowest_node(&lca); |
147 | if lca.first_token() == Some(fst_expanded) && lca.last_token() == Some(lst_expanded) { | 148 | if lca.first_token() == Some(fst_expanded) && lca.last_token() == Some(lst_expanded) { |
148 | lca = lca.parent()?; | 149 | lca = lca.parent()?; |
@@ -151,9 +152,13 @@ fn extend_tokens_from_range( | |||
151 | }; | 152 | }; |
152 | 153 | ||
153 | // Compute parent node range | 154 | // Compute parent node range |
154 | let validate = |token: &SyntaxToken| { | 155 | let validate = |token: &SyntaxToken| -> bool { |
155 | let expanded = sema.descend_into_macros(token.clone()); | 156 | let expanded = sema.descend_into_macros(token.clone()); |
156 | algo::least_common_ancestor(&extended, &expanded.parent()).as_ref() == Some(&extended) | 157 | let parent = match expanded.parent() { |
158 | Some(it) => it, | ||
159 | None => return false, | ||
160 | }; | ||
161 | algo::least_common_ancestor(&extended, &parent).as_ref() == Some(&extended) | ||
157 | }; | 162 | }; |
158 | 163 | ||
159 | // Find the first and last text range under expanded parent | 164 | // Find the first and last text range under expanded parent |
diff --git a/crates/ide/src/goto_definition.rs b/crates/ide/src/goto_definition.rs index e8f31e4b1..6986477a5 100644 --- a/crates/ide/src/goto_definition.rs +++ b/crates/ide/src/goto_definition.rs | |||
@@ -30,7 +30,7 @@ pub(crate) fn goto_definition( | |||
30 | let file = sema.parse(position.file_id).syntax().clone(); | 30 | let file = sema.parse(position.file_id).syntax().clone(); |
31 | let original_token = pick_best(file.token_at_offset(position.offset))?; | 31 | let original_token = pick_best(file.token_at_offset(position.offset))?; |
32 | let token = sema.descend_into_macros(original_token.clone()); | 32 | let token = sema.descend_into_macros(original_token.clone()); |
33 | let parent = token.parent(); | 33 | let parent = token.parent()?; |
34 | if let Some(comment) = ast::Comment::cast(token) { | 34 | if let Some(comment) = ast::Comment::cast(token) { |
35 | let nav = def_for_doc_comment(&sema, position, &comment)?.try_to_nav(db)?; | 35 | let nav = def_for_doc_comment(&sema, position, &comment)?.try_to_nav(db)?; |
36 | return Some(RangeInfo::new(original_token.text_range(), vec![nav])); | 36 | return Some(RangeInfo::new(original_token.text_range(), vec![nav])); |
@@ -63,7 +63,7 @@ fn def_for_doc_comment( | |||
63 | position: FilePosition, | 63 | position: FilePosition, |
64 | doc_comment: &ast::Comment, | 64 | doc_comment: &ast::Comment, |
65 | ) -> Option<hir::ModuleDef> { | 65 | ) -> Option<hir::ModuleDef> { |
66 | let parent = doc_comment.syntax().parent(); | 66 | let parent = doc_comment.syntax().parent()?; |
67 | let (link, ns) = extract_positioned_link_from_comment(position, doc_comment)?; | 67 | let (link, ns) = extract_positioned_link_from_comment(position, doc_comment)?; |
68 | 68 | ||
69 | let def = doc_owner_to_def(sema, parent)?; | 69 | let def = doc_owner_to_def(sema, parent)?; |
diff --git a/crates/ide/src/goto_type_definition.rs b/crates/ide/src/goto_type_definition.rs index 369a59820..2d38cb112 100644 --- a/crates/ide/src/goto_type_definition.rs +++ b/crates/ide/src/goto_type_definition.rs | |||
@@ -22,7 +22,7 @@ pub(crate) fn goto_type_definition( | |||
22 | let token: SyntaxToken = pick_best(file.syntax().token_at_offset(position.offset))?; | 22 | let token: SyntaxToken = pick_best(file.syntax().token_at_offset(position.offset))?; |
23 | let token: SyntaxToken = sema.descend_into_macros(token); | 23 | let token: SyntaxToken = sema.descend_into_macros(token); |
24 | 24 | ||
25 | let (ty, node) = sema.ancestors_with_macros(token.parent()).find_map(|node| { | 25 | let (ty, node) = sema.token_ancestors_with_macros(token).find_map(|node| { |
26 | let ty = match_ast! { | 26 | let ty = match_ast! { |
27 | match node { | 27 | match node { |
28 | ast::Expr(it) => sema.type_of_expr(&it)?, | 28 | ast::Expr(it) => sema.type_of_expr(&it)?, |
diff --git a/crates/ide/src/hover.rs b/crates/ide/src/hover.rs index ea45086ce..8d45b4875 100644 --- a/crates/ide/src/hover.rs +++ b/crates/ide/src/hover.rs | |||
@@ -1,7 +1,7 @@ | |||
1 | use either::Either; | 1 | use either::Either; |
2 | use hir::{ | 2 | use hir::{ |
3 | Adt, AsAssocItem, AssocItemContainer, FieldSource, GenericParam, HasAttrs, HasSource, | 3 | Adt, AsAssocItem, AssocItemContainer, GenericParam, HasAttrs, HasSource, HirDisplay, Module, |
4 | HirDisplay, Module, ModuleDef, ModuleSource, Semantics, | 4 | ModuleDef, Semantics, |
5 | }; | 5 | }; |
6 | use ide_db::{ | 6 | use ide_db::{ |
7 | base_db::SourceDatabase, | 7 | base_db::SourceDatabase, |
@@ -14,7 +14,7 @@ use stdx::format_to; | |||
14 | use syntax::{ast, match_ast, AstNode, SyntaxKind::*, SyntaxToken, TokenAtOffset, T}; | 14 | use syntax::{ast, match_ast, AstNode, SyntaxKind::*, SyntaxToken, TokenAtOffset, T}; |
15 | 15 | ||
16 | use crate::{ | 16 | use crate::{ |
17 | display::{macro_label, ShortLabel, TryToNav}, | 17 | display::{macro_label, TryToNav}, |
18 | doc_links::{remove_links, rewrite_links}, | 18 | doc_links::{remove_links, rewrite_links}, |
19 | markdown_remove::remove_markdown, | 19 | markdown_remove::remove_markdown, |
20 | markup::Markup, | 20 | markup::Markup, |
@@ -92,7 +92,7 @@ pub(crate) fn hover( | |||
92 | 92 | ||
93 | let mut res = HoverResult::default(); | 93 | let mut res = HoverResult::default(); |
94 | 94 | ||
95 | let node = token.parent(); | 95 | let node = token.parent()?; |
96 | let definition = match_ast! { | 96 | let definition = match_ast! { |
97 | match node { | 97 | match node { |
98 | // we don't use NameClass::referenced_or_defined here as we do not want to resolve | 98 | // we don't use NameClass::referenced_or_defined here as we do not want to resolve |
@@ -335,34 +335,18 @@ fn hover_for_definition( | |||
335 | let label = macro_label(&it.source(db)?.value); | 335 | let label = macro_label(&it.source(db)?.value); |
336 | from_def_source_labeled(db, it, Some(label), mod_path) | 336 | from_def_source_labeled(db, it, Some(label), mod_path) |
337 | } | 337 | } |
338 | Definition::Field(def) => { | 338 | Definition::Field(def) => from_hir_fmt(db, def, mod_path), |
339 | let src = def.source(db)?.value; | ||
340 | if let FieldSource::Named(it) = src { | ||
341 | from_def_source_labeled(db, def, it.short_label(), mod_path) | ||
342 | } else { | ||
343 | None | ||
344 | } | ||
345 | } | ||
346 | Definition::ModuleDef(it) => match it { | 339 | Definition::ModuleDef(it) => match it { |
347 | ModuleDef::Module(it) => from_def_source_labeled( | 340 | ModuleDef::Module(it) => from_hir_fmt(db, it, mod_path), |
348 | db, | 341 | ModuleDef::Function(it) => from_hir_fmt(db, it, mod_path), |
349 | it, | 342 | ModuleDef::Adt(Adt::Struct(it)) => from_hir_fmt(db, it, mod_path), |
350 | match it.definition_source(db).value { | 343 | ModuleDef::Adt(Adt::Union(it)) => from_hir_fmt(db, it, mod_path), |
351 | ModuleSource::Module(it) => it.short_label(), | 344 | ModuleDef::Adt(Adt::Enum(it)) => from_hir_fmt(db, it, mod_path), |
352 | ModuleSource::SourceFile(it) => it.short_label(), | 345 | ModuleDef::Variant(it) => from_hir_fmt(db, it, mod_path), |
353 | ModuleSource::BlockExpr(it) => it.short_label(), | 346 | ModuleDef::Const(it) => from_hir_fmt(db, it, mod_path), |
354 | }, | 347 | ModuleDef::Static(it) => from_hir_fmt(db, it, mod_path), |
355 | mod_path, | 348 | ModuleDef::Trait(it) => from_hir_fmt(db, it, mod_path), |
356 | ), | 349 | ModuleDef::TypeAlias(it) => from_hir_fmt(db, it, mod_path), |
357 | ModuleDef::Function(it) => from_def_source(db, it, mod_path), | ||
358 | ModuleDef::Adt(Adt::Struct(it)) => from_def_source(db, it, mod_path), | ||
359 | ModuleDef::Adt(Adt::Union(it)) => from_def_source(db, it, mod_path), | ||
360 | ModuleDef::Adt(Adt::Enum(it)) => from_def_source(db, it, mod_path), | ||
361 | ModuleDef::Variant(it) => from_def_source(db, it, mod_path), | ||
362 | ModuleDef::Const(it) => from_def_source(db, it, mod_path), | ||
363 | ModuleDef::Static(it) => from_def_source(db, it, mod_path), | ||
364 | ModuleDef::Trait(it) => from_def_source(db, it, mod_path), | ||
365 | ModuleDef::TypeAlias(it) => from_def_source(db, it, mod_path), | ||
366 | ModuleDef::BuiltinType(it) => famous_defs | 350 | ModuleDef::BuiltinType(it) => famous_defs |
367 | .and_then(|fd| hover_for_builtin(fd, it)) | 351 | .and_then(|fd| hover_for_builtin(fd, it)) |
368 | .or_else(|| Some(Markup::fenced_block(&it.name()))), | 352 | .or_else(|| Some(Markup::fenced_block(&it.name()))), |
@@ -370,26 +354,25 @@ fn hover_for_definition( | |||
370 | Definition::Local(it) => hover_for_local(it, db), | 354 | Definition::Local(it) => hover_for_local(it, db), |
371 | Definition::SelfType(impl_def) => { | 355 | Definition::SelfType(impl_def) => { |
372 | impl_def.target_ty(db).as_adt().and_then(|adt| match adt { | 356 | impl_def.target_ty(db).as_adt().and_then(|adt| match adt { |
373 | Adt::Struct(it) => from_def_source(db, it, mod_path), | 357 | Adt::Struct(it) => from_hir_fmt(db, it, mod_path), |
374 | Adt::Union(it) => from_def_source(db, it, mod_path), | 358 | Adt::Union(it) => from_hir_fmt(db, it, mod_path), |
375 | Adt::Enum(it) => from_def_source(db, it, mod_path), | 359 | Adt::Enum(it) => from_hir_fmt(db, it, mod_path), |
376 | }) | 360 | }) |
377 | } | 361 | } |
378 | Definition::Label(it) => Some(Markup::fenced_block(&it.name(db))), | 362 | Definition::Label(it) => Some(Markup::fenced_block(&it.name(db))), |
379 | Definition::GenericParam(it) => match it { | 363 | Definition::GenericParam(it) => match it { |
380 | GenericParam::TypeParam(it) => Some(Markup::fenced_block(&it.display(db))), | 364 | GenericParam::TypeParam(it) => Some(Markup::fenced_block(&it.display(db))), |
381 | GenericParam::LifetimeParam(it) => Some(Markup::fenced_block(&it.name(db))), | 365 | GenericParam::LifetimeParam(it) => Some(Markup::fenced_block(&it.name(db))), |
382 | GenericParam::ConstParam(it) => from_def_source(db, it, None), | 366 | GenericParam::ConstParam(it) => Some(Markup::fenced_block(&it.display(db))), |
383 | }, | 367 | }, |
384 | }; | 368 | }; |
385 | 369 | ||
386 | fn from_def_source<A, D>(db: &RootDatabase, def: D, mod_path: Option<String>) -> Option<Markup> | 370 | fn from_hir_fmt<D>(db: &RootDatabase, def: D, mod_path: Option<String>) -> Option<Markup> |
387 | where | 371 | where |
388 | D: HasSource<Ast = A> + HasAttrs + Copy, | 372 | D: HasAttrs + HirDisplay, |
389 | A: ShortLabel, | ||
390 | { | 373 | { |
391 | let short_label = def.source(db)?.value.short_label(); | 374 | let label = def.display(db).to_string(); |
392 | from_def_source_labeled(db, def, short_label, mod_path) | 375 | from_def_source_labeled(db, def, Some(label), mod_path) |
393 | } | 376 | } |
394 | 377 | ||
395 | fn from_def_source_labeled<D>( | 378 | fn from_def_source_labeled<D>( |
@@ -438,7 +421,7 @@ fn hover_for_keyword( | |||
438 | if !token.kind().is_keyword() { | 421 | if !token.kind().is_keyword() { |
439 | return None; | 422 | return None; |
440 | } | 423 | } |
441 | let famous_defs = FamousDefs(&sema, sema.scope(&token.parent()).krate()); | 424 | let famous_defs = FamousDefs(&sema, sema.scope(&token.parent()?).krate()); |
442 | // std exposes {}_keyword modules with docstrings on the root to document keywords | 425 | // std exposes {}_keyword modules with docstrings on the root to document keywords |
443 | let keyword_mod = format!("{}_keyword", token.text()); | 426 | let keyword_mod = format!("{}_keyword", token.text()); |
444 | let doc_owner = find_std_module(&famous_defs, &keyword_mod)?; | 427 | let doc_owner = find_std_module(&famous_defs, &keyword_mod)?; |
@@ -670,7 +653,9 @@ fn main() { let foo_test = fo$0o(); } | |||
670 | ``` | 653 | ``` |
671 | 654 | ||
672 | ```rust | 655 | ```rust |
673 | pub fn foo<'a, T: AsRef<str>>(b: &'a T) -> &'a str | 656 | pub fn foo<'a, T>(b: &'a T) -> &'a str |
657 | where | ||
658 | T: AsRef<str>, | ||
674 | ``` | 659 | ``` |
675 | "#]], | 660 | "#]], |
676 | ); | 661 | ); |
@@ -878,7 +863,7 @@ fn main() { So$0me(12); } | |||
878 | ``` | 863 | ``` |
879 | 864 | ||
880 | ```rust | 865 | ```rust |
881 | Some | 866 | Some(T) |
882 | ``` | 867 | ``` |
883 | "#]], | 868 | "#]], |
884 | ); | 869 | ); |
@@ -944,7 +929,7 @@ fn main() { | |||
944 | ``` | 929 | ``` |
945 | 930 | ||
946 | ```rust | 931 | ```rust |
947 | Some | 932 | Some(T) |
948 | ``` | 933 | ``` |
949 | 934 | ||
950 | --- | 935 | --- |
@@ -1441,13 +1426,14 @@ fn bar() { fo$0o(); } | |||
1441 | ``` | 1426 | ``` |
1442 | "#]], | 1427 | "#]], |
1443 | ); | 1428 | ); |
1429 | // Top level `pub(crate)` will be displayed as no visibility. | ||
1444 | check( | 1430 | check( |
1445 | r#"pub(crate) async unsafe extern "C" fn foo$0() {}"#, | 1431 | r#"mod m { pub(crate) async unsafe extern "C" fn foo$0() {} }"#, |
1446 | expect![[r#" | 1432 | expect![[r#" |
1447 | *foo* | 1433 | *foo* |
1448 | 1434 | ||
1449 | ```rust | 1435 | ```rust |
1450 | test | 1436 | test::m |
1451 | ``` | 1437 | ``` |
1452 | 1438 | ||
1453 | ```rust | 1439 | ```rust |
@@ -1489,11 +1475,18 @@ extern crate st$0d; | |||
1489 | //! abc123 | 1475 | //! abc123 |
1490 | "#, | 1476 | "#, |
1491 | expect![[r#" | 1477 | expect![[r#" |
1492 | *std* | 1478 | *std* |
1493 | Standard library for this test | 1479 | |
1480 | ```rust | ||
1481 | extern crate std | ||
1482 | ``` | ||
1494 | 1483 | ||
1495 | Printed? | 1484 | --- |
1496 | abc123 | 1485 | |
1486 | Standard library for this test | ||
1487 | |||
1488 | Printed? | ||
1489 | abc123 | ||
1497 | "#]], | 1490 | "#]], |
1498 | ); | 1491 | ); |
1499 | check( | 1492 | check( |
@@ -1507,11 +1500,18 @@ extern crate std as ab$0c; | |||
1507 | //! abc123 | 1500 | //! abc123 |
1508 | "#, | 1501 | "#, |
1509 | expect![[r#" | 1502 | expect![[r#" |
1510 | *abc* | 1503 | *abc* |
1511 | Standard library for this test | 1504 | |
1505 | ```rust | ||
1506 | extern crate std | ||
1507 | ``` | ||
1508 | |||
1509 | --- | ||
1512 | 1510 | ||
1513 | Printed? | 1511 | Standard library for this test |
1514 | abc123 | 1512 | |
1513 | Printed? | ||
1514 | abc123 | ||
1515 | "#]], | 1515 | "#]], |
1516 | ); | 1516 | ); |
1517 | } | 1517 | } |
@@ -2021,7 +2021,7 @@ enum E { | |||
2021 | ``` | 2021 | ``` |
2022 | 2022 | ||
2023 | ```rust | 2023 | ```rust |
2024 | V | 2024 | V { field: i32 } |
2025 | ``` | 2025 | ``` |
2026 | 2026 | ||
2027 | --- | 2027 | --- |
@@ -2417,7 +2417,7 @@ fn main() { let s$0t = S{ f1:Arg(0) }; } | |||
2417 | focus_range: 24..25, | 2417 | focus_range: 24..25, |
2418 | name: "S", | 2418 | name: "S", |
2419 | kind: Struct, | 2419 | kind: Struct, |
2420 | description: "struct S", | 2420 | description: "struct S<T>", |
2421 | }, | 2421 | }, |
2422 | }, | 2422 | }, |
2423 | HoverGotoTypeData { | 2423 | HoverGotoTypeData { |
@@ -2463,7 +2463,7 @@ fn main() { let s$0t = S{ f1: S{ f1: Arg(0) } }; } | |||
2463 | focus_range: 24..25, | 2463 | focus_range: 24..25, |
2464 | name: "S", | 2464 | name: "S", |
2465 | kind: Struct, | 2465 | kind: Struct, |
2466 | description: "struct S", | 2466 | description: "struct S<T>", |
2467 | }, | 2467 | }, |
2468 | }, | 2468 | }, |
2469 | HoverGotoTypeData { | 2469 | HoverGotoTypeData { |
@@ -2605,7 +2605,7 @@ fn main() { let s$0t = foo(); } | |||
2605 | focus_range: 6..9, | 2605 | focus_range: 6..9, |
2606 | name: "Foo", | 2606 | name: "Foo", |
2607 | kind: Trait, | 2607 | kind: Trait, |
2608 | description: "trait Foo", | 2608 | description: "trait Foo<T>", |
2609 | }, | 2609 | }, |
2610 | }, | 2610 | }, |
2611 | HoverGotoTypeData { | 2611 | HoverGotoTypeData { |
@@ -2702,7 +2702,7 @@ fn main() { let s$0t = foo(); } | |||
2702 | focus_range: 6..9, | 2702 | focus_range: 6..9, |
2703 | name: "Foo", | 2703 | name: "Foo", |
2704 | kind: Trait, | 2704 | kind: Trait, |
2705 | description: "trait Foo", | 2705 | description: "trait Foo<T>", |
2706 | }, | 2706 | }, |
2707 | }, | 2707 | }, |
2708 | HoverGotoTypeData { | 2708 | HoverGotoTypeData { |
@@ -2715,7 +2715,7 @@ fn main() { let s$0t = foo(); } | |||
2715 | focus_range: 22..25, | 2715 | focus_range: 22..25, |
2716 | name: "Bar", | 2716 | name: "Bar", |
2717 | kind: Trait, | 2717 | kind: Trait, |
2718 | description: "trait Bar", | 2718 | description: "trait Bar<T>", |
2719 | }, | 2719 | }, |
2720 | }, | 2720 | }, |
2721 | HoverGotoTypeData { | 2721 | HoverGotoTypeData { |
@@ -2819,7 +2819,7 @@ fn foo(ar$0g: &impl Foo + Bar<S>) {} | |||
2819 | focus_range: 19..22, | 2819 | focus_range: 19..22, |
2820 | name: "Bar", | 2820 | name: "Bar", |
2821 | kind: Trait, | 2821 | kind: Trait, |
2822 | description: "trait Bar", | 2822 | description: "trait Bar<T>", |
2823 | }, | 2823 | }, |
2824 | }, | 2824 | }, |
2825 | HoverGotoTypeData { | 2825 | HoverGotoTypeData { |
@@ -2916,7 +2916,7 @@ fn foo(ar$0g: &impl Foo<S>) {} | |||
2916 | focus_range: 6..9, | 2916 | focus_range: 6..9, |
2917 | name: "Foo", | 2917 | name: "Foo", |
2918 | kind: Trait, | 2918 | kind: Trait, |
2919 | description: "trait Foo", | 2919 | description: "trait Foo<T>", |
2920 | }, | 2920 | }, |
2921 | }, | 2921 | }, |
2922 | HoverGotoTypeData { | 2922 | HoverGotoTypeData { |
@@ -2966,7 +2966,7 @@ fn main() { let s$0t = foo(); } | |||
2966 | focus_range: 49..50, | 2966 | focus_range: 49..50, |
2967 | name: "B", | 2967 | name: "B", |
2968 | kind: Struct, | 2968 | kind: Struct, |
2969 | description: "struct B", | 2969 | description: "struct B<T>", |
2970 | }, | 2970 | }, |
2971 | }, | 2971 | }, |
2972 | HoverGotoTypeData { | 2972 | HoverGotoTypeData { |
@@ -3042,7 +3042,7 @@ fn foo(ar$0g: &dyn Foo<S>) {} | |||
3042 | focus_range: 6..9, | 3042 | focus_range: 6..9, |
3043 | name: "Foo", | 3043 | name: "Foo", |
3044 | kind: Trait, | 3044 | kind: Trait, |
3045 | description: "trait Foo", | 3045 | description: "trait Foo<T>", |
3046 | }, | 3046 | }, |
3047 | }, | 3047 | }, |
3048 | HoverGotoTypeData { | 3048 | HoverGotoTypeData { |
@@ -3090,7 +3090,7 @@ fn foo(a$0rg: &impl ImplTrait<B<dyn DynTrait<B<S>>>>) {} | |||
3090 | focus_range: 6..15, | 3090 | focus_range: 6..15, |
3091 | name: "ImplTrait", | 3091 | name: "ImplTrait", |
3092 | kind: Trait, | 3092 | kind: Trait, |
3093 | description: "trait ImplTrait", | 3093 | description: "trait ImplTrait<T>", |
3094 | }, | 3094 | }, |
3095 | }, | 3095 | }, |
3096 | HoverGotoTypeData { | 3096 | HoverGotoTypeData { |
@@ -3103,7 +3103,7 @@ fn foo(a$0rg: &impl ImplTrait<B<dyn DynTrait<B<S>>>>) {} | |||
3103 | focus_range: 50..51, | 3103 | focus_range: 50..51, |
3104 | name: "B", | 3104 | name: "B", |
3105 | kind: Struct, | 3105 | kind: Struct, |
3106 | description: "struct B", | 3106 | description: "struct B<T>", |
3107 | }, | 3107 | }, |
3108 | }, | 3108 | }, |
3109 | HoverGotoTypeData { | 3109 | HoverGotoTypeData { |
@@ -3116,7 +3116,7 @@ fn foo(a$0rg: &impl ImplTrait<B<dyn DynTrait<B<S>>>>) {} | |||
3116 | focus_range: 28..36, | 3116 | focus_range: 28..36, |
3117 | name: "DynTrait", | 3117 | name: "DynTrait", |
3118 | kind: Trait, | 3118 | kind: Trait, |
3119 | description: "trait DynTrait", | 3119 | description: "trait DynTrait<T>", |
3120 | }, | 3120 | }, |
3121 | }, | 3121 | }, |
3122 | HoverGotoTypeData { | 3122 | HoverGotoTypeData { |
@@ -3582,6 +3582,17 @@ mod foo$0; | |||
3582 | "#, | 3582 | "#, |
3583 | expect![[r#" | 3583 | expect![[r#" |
3584 | *foo* | 3584 | *foo* |
3585 | |||
3586 | ```rust | ||
3587 | test | ||
3588 | ``` | ||
3589 | |||
3590 | ```rust | ||
3591 | mod foo | ||
3592 | ``` | ||
3593 | |||
3594 | --- | ||
3595 | |||
3585 | For the horde! | 3596 | For the horde! |
3586 | "#]], | 3597 | "#]], |
3587 | ); | 3598 | ); |
@@ -3606,7 +3617,7 @@ use foo::bar::{self$0}; | |||
3606 | ``` | 3617 | ``` |
3607 | 3618 | ||
3608 | ```rust | 3619 | ```rust |
3609 | pub mod bar | 3620 | mod bar |
3610 | ``` | 3621 | ``` |
3611 | 3622 | ||
3612 | --- | 3623 | --- |
@@ -3657,4 +3668,43 @@ cosnt _: &str$0 = ""; }"#; | |||
3657 | "#]], | 3668 | "#]], |
3658 | ); | 3669 | ); |
3659 | } | 3670 | } |
3671 | |||
3672 | #[test] | ||
3673 | fn hover_macro_expanded_function() { | ||
3674 | check( | ||
3675 | r#" | ||
3676 | struct S<'a, T>(&'a T); | ||
3677 | trait Clone {} | ||
3678 | macro_rules! foo { | ||
3679 | () => { | ||
3680 | fn bar<'t, T: Clone + 't>(s: &mut S<'t, T>, t: u32) -> *mut u32 where | ||
3681 | 't: 't + 't, | ||
3682 | for<'a> T: Clone + 'a | ||
3683 | { 0 as _ } | ||
3684 | }; | ||
3685 | } | ||
3686 | |||
3687 | foo!(); | ||
3688 | |||
3689 | fn main() { | ||
3690 | bar$0; | ||
3691 | } | ||
3692 | "#, | ||
3693 | expect![[r#" | ||
3694 | *bar* | ||
3695 | |||
3696 | ```rust | ||
3697 | test | ||
3698 | ``` | ||
3699 | |||
3700 | ```rust | ||
3701 | fn bar<'t, T>(s: &mut S<'t, T>, t: u32) -> *mut u32 | ||
3702 | where | ||
3703 | T: Clone + 't, | ||
3704 | 't: 't + 't, | ||
3705 | for<'a> T: Clone + 'a, | ||
3706 | ``` | ||
3707 | "#]], | ||
3708 | ) | ||
3709 | } | ||
3660 | } | 3710 | } |
diff --git a/crates/ide/src/join_lines.rs b/crates/ide/src/join_lines.rs index d571ed559..4b25135cd 100644 --- a/crates/ide/src/join_lines.rs +++ b/crates/ide/src/join_lines.rs | |||
@@ -32,29 +32,35 @@ pub(crate) fn join_lines(file: &SourceFile, range: TextRange) -> TextEdit { | |||
32 | range | 32 | range |
33 | }; | 33 | }; |
34 | 34 | ||
35 | let node = match file.syntax().covering_element(range) { | ||
36 | NodeOrToken::Node(node) => node, | ||
37 | NodeOrToken::Token(token) => token.parent(), | ||
38 | }; | ||
39 | let mut edit = TextEdit::builder(); | 35 | let mut edit = TextEdit::builder(); |
40 | for token in node.descendants_with_tokens().filter_map(|it| it.into_token()) { | 36 | match file.syntax().covering_element(range) { |
41 | let range = match range.intersect(token.text_range()) { | 37 | NodeOrToken::Node(node) => { |
42 | Some(range) => range, | 38 | for token in node.descendants_with_tokens().filter_map(|it| it.into_token()) { |
43 | None => continue, | 39 | remove_newlines(&mut edit, &token, range) |
44 | } - token.text_range().start(); | ||
45 | let text = token.text(); | ||
46 | for (pos, _) in text[range].bytes().enumerate().filter(|&(_, b)| b == b'\n') { | ||
47 | let pos: TextSize = (pos as u32).into(); | ||
48 | let offset = token.text_range().start() + range.start() + pos; | ||
49 | if !edit.invalidates_offset(offset) { | ||
50 | remove_newline(&mut edit, &token, offset); | ||
51 | } | 40 | } |
52 | } | 41 | } |
53 | } | 42 | NodeOrToken::Token(token) => remove_newlines(&mut edit, &token, range), |
54 | 43 | }; | |
55 | edit.finish() | 44 | edit.finish() |
56 | } | 45 | } |
57 | 46 | ||
47 | fn remove_newlines(edit: &mut TextEditBuilder, token: &SyntaxToken, range: TextRange) { | ||
48 | let intersection = match range.intersect(token.text_range()) { | ||
49 | Some(range) => range, | ||
50 | None => return, | ||
51 | }; | ||
52 | |||
53 | let range = intersection - token.text_range().start(); | ||
54 | let text = token.text(); | ||
55 | for (pos, _) in text[range].bytes().enumerate().filter(|&(_, b)| b == b'\n') { | ||
56 | let pos: TextSize = (pos as u32).into(); | ||
57 | let offset = token.text_range().start() + range.start() + pos; | ||
58 | if !edit.invalidates_offset(offset) { | ||
59 | remove_newline(edit, &token, offset); | ||
60 | } | ||
61 | } | ||
62 | } | ||
63 | |||
58 | fn remove_newline(edit: &mut TextEditBuilder, token: &SyntaxToken, offset: TextSize) { | 64 | fn remove_newline(edit: &mut TextEditBuilder, token: &SyntaxToken, offset: TextSize) { |
59 | if token.kind() != WHITESPACE || token.text().bytes().filter(|&b| b == b'\n').count() != 1 { | 65 | if token.kind() != WHITESPACE || token.text().bytes().filter(|&b| b == b'\n').count() != 1 { |
60 | let mut string_open_quote = false; | 66 | let mut string_open_quote = false; |
@@ -148,7 +154,7 @@ fn has_comma_after(node: &SyntaxNode) -> bool { | |||
148 | } | 154 | } |
149 | 155 | ||
150 | fn join_single_expr_block(edit: &mut TextEditBuilder, token: &SyntaxToken) -> Option<()> { | 156 | fn join_single_expr_block(edit: &mut TextEditBuilder, token: &SyntaxToken) -> Option<()> { |
151 | let block_expr = ast::BlockExpr::cast(token.parent())?; | 157 | let block_expr = ast::BlockExpr::cast(token.parent()?)?; |
152 | if !block_expr.is_standalone() { | 158 | if !block_expr.is_standalone() { |
153 | return None; | 159 | return None; |
154 | } | 160 | } |
@@ -170,7 +176,7 @@ fn join_single_expr_block(edit: &mut TextEditBuilder, token: &SyntaxToken) -> Op | |||
170 | } | 176 | } |
171 | 177 | ||
172 | fn join_single_use_tree(edit: &mut TextEditBuilder, token: &SyntaxToken) -> Option<()> { | 178 | fn join_single_use_tree(edit: &mut TextEditBuilder, token: &SyntaxToken) -> Option<()> { |
173 | let use_tree_list = ast::UseTreeList::cast(token.parent())?; | 179 | let use_tree_list = ast::UseTreeList::cast(token.parent()?)?; |
174 | let (tree,) = use_tree_list.use_trees().collect_tuple()?; | 180 | let (tree,) = use_tree_list.use_trees().collect_tuple()?; |
175 | edit.replace(use_tree_list.syntax().text_range(), tree.syntax().text().to_string()); | 181 | edit.replace(use_tree_list.syntax().text_range(), tree.syntax().text().to_string()); |
176 | Some(()) | 182 | Some(()) |
diff --git a/crates/ide/src/matching_brace.rs b/crates/ide/src/matching_brace.rs index 000c412d9..4241a6dac 100644 --- a/crates/ide/src/matching_brace.rs +++ b/crates/ide/src/matching_brace.rs | |||
@@ -25,7 +25,7 @@ pub(crate) fn matching_brace(file: &SourceFile, offset: TextSize) -> Option<Text | |||
25 | Some((node, idx)) | 25 | Some((node, idx)) |
26 | }) | 26 | }) |
27 | .next()?; | 27 | .next()?; |
28 | let parent = brace_token.parent(); | 28 | let parent = brace_token.parent()?; |
29 | if brace_token.kind() == T![|] && !ast::ParamList::can_cast(parent.kind()) { | 29 | if brace_token.kind() == T![|] && !ast::ParamList::can_cast(parent.kind()) { |
30 | cov_mark::hit!(pipes_not_braces); | 30 | cov_mark::hit!(pipes_not_braces); |
31 | return None; | 31 | return None; |
diff --git a/crates/ide/src/parent_module.rs b/crates/ide/src/parent_module.rs index 03d71b380..22b0d6ecb 100644 --- a/crates/ide/src/parent_module.rs +++ b/crates/ide/src/parent_module.rs | |||
@@ -1,6 +1,7 @@ | |||
1 | use hir::Semantics; | 1 | use hir::Semantics; |
2 | use ide_db::base_db::{CrateId, FileId, FilePosition}; | 2 | use ide_db::base_db::{CrateId, FileId, FilePosition}; |
3 | use ide_db::RootDatabase; | 3 | use ide_db::RootDatabase; |
4 | use itertools::Itertools; | ||
4 | use syntax::{ | 5 | use syntax::{ |
5 | algo::find_node_at_offset, | 6 | algo::find_node_at_offset, |
6 | ast::{self, AstNode}, | 7 | ast::{self, AstNode}, |
@@ -18,8 +19,7 @@ use crate::NavigationTarget; | |||
18 | // | VS Code | **Rust Analyzer: Locate parent module** | 19 | // | VS Code | **Rust Analyzer: Locate parent module** |
19 | // |=== | 20 | // |=== |
20 | 21 | ||
21 | /// This returns `Vec` because a module may be included from several places. We | 22 | /// This returns `Vec` because a module may be included from several places. |
22 | /// don't handle this case yet though, so the Vec has length at most one. | ||
23 | pub(crate) fn parent_module(db: &RootDatabase, position: FilePosition) -> Vec<NavigationTarget> { | 23 | pub(crate) fn parent_module(db: &RootDatabase, position: FilePosition) -> Vec<NavigationTarget> { |
24 | let sema = Semantics::new(db); | 24 | let sema = Semantics::new(db); |
25 | let source_file = sema.parse(position.file_id); | 25 | let source_file = sema.parse(position.file_id); |
@@ -37,27 +37,23 @@ pub(crate) fn parent_module(db: &RootDatabase, position: FilePosition) -> Vec<Na | |||
37 | } | 37 | } |
38 | } | 38 | } |
39 | 39 | ||
40 | let module = match module { | 40 | match module { |
41 | Some(module) => sema.to_def(&module), | 41 | Some(module) => sema |
42 | None => sema.to_module_def(position.file_id), | 42 | .to_def(&module) |
43 | }; | 43 | .into_iter() |
44 | let module = match module { | 44 | .map(|module| NavigationTarget::from_module_to_decl(db, module)) |
45 | None => return Vec::new(), | 45 | .collect(), |
46 | Some(it) => it, | 46 | None => sema |
47 | }; | 47 | .to_module_defs(position.file_id) |
48 | let nav = NavigationTarget::from_module_to_decl(db, module); | 48 | .map(|module| NavigationTarget::from_module_to_decl(db, module)) |
49 | vec![nav] | 49 | .collect(), |
50 | } | ||
50 | } | 51 | } |
51 | 52 | ||
52 | /// Returns `Vec` for the same reason as `parent_module` | 53 | /// Returns `Vec` for the same reason as `parent_module` |
53 | pub(crate) fn crate_for(db: &RootDatabase, file_id: FileId) -> Vec<CrateId> { | 54 | pub(crate) fn crate_for(db: &RootDatabase, file_id: FileId) -> Vec<CrateId> { |
54 | let sema = Semantics::new(db); | 55 | let sema = Semantics::new(db); |
55 | let module = match sema.to_module_def(file_id) { | 56 | sema.to_module_defs(file_id).map(|module| module.krate().into()).unique().collect() |
56 | Some(it) => it, | ||
57 | None => return Vec::new(), | ||
58 | }; | ||
59 | let krate = module.krate(); | ||
60 | vec![krate.into()] | ||
61 | } | 57 | } |
62 | 58 | ||
63 | #[cfg(test)] | 59 | #[cfg(test)] |
@@ -67,11 +63,13 @@ mod tests { | |||
67 | use crate::fixture; | 63 | use crate::fixture; |
68 | 64 | ||
69 | fn check(ra_fixture: &str) { | 65 | fn check(ra_fixture: &str) { |
70 | let (analysis, position, expected) = fixture::nav_target_annotation(ra_fixture); | 66 | let (analysis, position, expected) = fixture::annotations(ra_fixture); |
71 | let mut navs = analysis.parent_module(position).unwrap(); | 67 | let navs = analysis.parent_module(position).unwrap(); |
72 | assert_eq!(navs.len(), 1); | 68 | let navs = navs |
73 | let nav = navs.pop().unwrap(); | 69 | .iter() |
74 | assert_eq!(expected, FileRange { file_id: nav.file_id, range: nav.focus_or_full_range() }); | 70 | .map(|nav| FileRange { file_id: nav.file_id, range: nav.focus_or_full_range() }) |
71 | .collect::<Vec<_>>(); | ||
72 | assert_eq!(expected.into_iter().map(|(fr, _)| fr).collect::<Vec<_>>(), navs); | ||
75 | } | 73 | } |
76 | 74 | ||
77 | #[test] | 75 | #[test] |
@@ -120,15 +118,46 @@ mod foo { | |||
120 | } | 118 | } |
121 | 119 | ||
122 | #[test] | 120 | #[test] |
123 | fn test_resolve_crate_root() { | 121 | fn test_resolve_multi_parent_module() { |
124 | let (analysis, file_id) = fixture::file( | 122 | check( |
125 | r#" | 123 | r#" |
126 | //- /main.rs | 124 | //- /main.rs |
127 | mod foo; | 125 | mod foo; |
126 | //^^^ | ||
127 | #[path = "foo.rs"] | ||
128 | mod bar; | ||
129 | //^^^ | ||
130 | //- /foo.rs | ||
131 | $0 | ||
132 | "#, | ||
133 | ); | ||
134 | } | ||
135 | |||
136 | #[test] | ||
137 | fn test_resolve_crate_root() { | ||
138 | let (analysis, file_id) = fixture::file( | ||
139 | r#" | ||
128 | //- /foo.rs | 140 | //- /foo.rs |
129 | $0 | 141 | $0 |
142 | //- /main.rs | ||
143 | mod foo; | ||
130 | "#, | 144 | "#, |
131 | ); | 145 | ); |
132 | assert_eq!(analysis.crate_for(file_id).unwrap().len(), 1); | 146 | assert_eq!(analysis.crate_for(file_id).unwrap().len(), 1); |
133 | } | 147 | } |
148 | |||
149 | #[test] | ||
150 | fn test_resolve_multi_parent_crate() { | ||
151 | let (analysis, file_id) = fixture::file( | ||
152 | r#" | ||
153 | //- /baz.rs | ||
154 | $0 | ||
155 | //- /foo.rs crate:foo | ||
156 | mod baz; | ||
157 | //- /bar.rs crate:bar | ||
158 | mod baz; | ||
159 | "#, | ||
160 | ); | ||
161 | assert_eq!(analysis.crate_for(file_id).unwrap().len(), 2); | ||
162 | } | ||
134 | } | 163 | } |
diff --git a/crates/ide/src/references.rs b/crates/ide/src/references.rs index e10a3ccf7..379674530 100644 --- a/crates/ide/src/references.rs +++ b/crates/ide/src/references.rs | |||
@@ -148,14 +148,15 @@ fn decl_access(def: &Definition, syntax: &SyntaxNode, range: TextRange) -> Optio | |||
148 | 148 | ||
149 | fn get_name_of_item_declaration(syntax: &SyntaxNode, position: FilePosition) -> Option<ast::Name> { | 149 | fn get_name_of_item_declaration(syntax: &SyntaxNode, position: FilePosition) -> Option<ast::Name> { |
150 | let token = syntax.token_at_offset(position.offset).right_biased()?; | 150 | let token = syntax.token_at_offset(position.offset).right_biased()?; |
151 | let token_parent = token.parent()?; | ||
151 | let kind = token.kind(); | 152 | let kind = token.kind(); |
152 | if kind == T![;] { | 153 | if kind == T![;] { |
153 | ast::Struct::cast(token.parent()) | 154 | ast::Struct::cast(token_parent) |
154 | .filter(|struct_| struct_.field_list().is_none()) | 155 | .filter(|struct_| struct_.field_list().is_none()) |
155 | .and_then(|struct_| struct_.name()) | 156 | .and_then(|struct_| struct_.name()) |
156 | } else if kind == T!['{'] { | 157 | } else if kind == T!['{'] { |
157 | match_ast! { | 158 | match_ast! { |
158 | match (token.parent()) { | 159 | match token_parent { |
159 | ast::RecordFieldList(rfl) => match_ast! { | 160 | ast::RecordFieldList(rfl) => match_ast! { |
160 | match (rfl.syntax().parent()?) { | 161 | match (rfl.syntax().parent()?) { |
161 | ast::Variant(it) => it.name(), | 162 | ast::Variant(it) => it.name(), |
@@ -169,7 +170,7 @@ fn get_name_of_item_declaration(syntax: &SyntaxNode, position: FilePosition) -> | |||
169 | } | 170 | } |
170 | } | 171 | } |
171 | } else if kind == T!['('] { | 172 | } else if kind == T!['('] { |
172 | let tfl = ast::TupleFieldList::cast(token.parent())?; | 173 | let tfl = ast::TupleFieldList::cast(token_parent)?; |
173 | match_ast! { | 174 | match_ast! { |
174 | match (tfl.syntax().parent()?) { | 175 | match (tfl.syntax().parent()?) { |
175 | ast::Variant(it) => it.name(), | 176 | ast::Variant(it) => it.name(), |
diff --git a/crates/ide/src/runnables.rs b/crates/ide/src/runnables.rs index 0c7a8fbf8..397e2126b 100644 --- a/crates/ide/src/runnables.rs +++ b/crates/ide/src/runnables.rs | |||
@@ -167,8 +167,7 @@ fn find_related_tests( | |||
167 | let functions = refs.iter().filter_map(|(range, _)| { | 167 | let functions = refs.iter().filter_map(|(range, _)| { |
168 | let token = file.token_at_offset(range.start()).next()?; | 168 | let token = file.token_at_offset(range.start()).next()?; |
169 | let token = sema.descend_into_macros(token); | 169 | let token = sema.descend_into_macros(token); |
170 | let syntax = token.parent(); | 170 | token.ancestors().find_map(ast::Fn::cast) |
171 | syntax.ancestors().find_map(ast::Fn::cast) | ||
172 | }); | 171 | }); |
173 | 172 | ||
174 | for fn_def in functions { | 173 | for fn_def in functions { |
diff --git a/crates/ide/src/syntax_highlighting.rs b/crates/ide/src/syntax_highlighting.rs index 9bed329d8..870146d24 100644 --- a/crates/ide/src/syntax_highlighting.rs +++ b/crates/ide/src/syntax_highlighting.rs | |||
@@ -64,7 +64,7 @@ pub(crate) fn highlight( | |||
64 | Some(range) => { | 64 | Some(range) => { |
65 | let node = match source_file.syntax().covering_element(range) { | 65 | let node = match source_file.syntax().covering_element(range) { |
66 | NodeOrToken::Node(it) => it, | 66 | NodeOrToken::Node(it) => it, |
67 | NodeOrToken::Token(it) => it.parent(), | 67 | NodeOrToken::Token(it) => it.parent().unwrap(), |
68 | }; | 68 | }; |
69 | (node, range) | 69 | (node, range) |
70 | } | 70 | } |
@@ -167,16 +167,19 @@ fn traverse( | |||
167 | let element_to_highlight = if current_macro_call.is_some() && element.kind() != COMMENT { | 167 | let element_to_highlight = if current_macro_call.is_some() && element.kind() != COMMENT { |
168 | // Inside a macro -- expand it first | 168 | // Inside a macro -- expand it first |
169 | let token = match element.clone().into_token() { | 169 | let token = match element.clone().into_token() { |
170 | Some(it) if it.parent().kind() == TOKEN_TREE => it, | 170 | Some(it) if it.parent().map_or(false, |it| it.kind() == TOKEN_TREE) => it, |
171 | _ => continue, | 171 | _ => continue, |
172 | }; | 172 | }; |
173 | let token = sema.descend_into_macros(token.clone()); | 173 | let token = sema.descend_into_macros(token.clone()); |
174 | let parent = token.parent(); | 174 | match token.parent() { |
175 | 175 | Some(parent) => { | |
176 | // We only care Name and Name_ref | 176 | // We only care Name and Name_ref |
177 | match (token.kind(), parent.kind()) { | 177 | match (token.kind(), parent.kind()) { |
178 | (IDENT, NAME) | (IDENT, NAME_REF) => parent.into(), | 178 | (IDENT, NAME) | (IDENT, NAME_REF) => parent.into(), |
179 | _ => token.into(), | 179 | _ => token.into(), |
180 | } | ||
181 | } | ||
182 | None => token.into(), | ||
180 | } | 183 | } |
181 | } else { | 184 | } else { |
182 | element.clone() | 185 | element.clone() |
diff --git a/crates/ide/src/syntax_highlighting/format.rs b/crates/ide/src/syntax_highlighting/format.rs index 8c67a0863..e503abc93 100644 --- a/crates/ide/src/syntax_highlighting/format.rs +++ b/crates/ide/src/syntax_highlighting/format.rs | |||
@@ -28,7 +28,7 @@ pub(super) fn highlight_format_string( | |||
28 | } | 28 | } |
29 | 29 | ||
30 | fn is_format_string(string: &ast::String) -> Option<()> { | 30 | 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(), "format_args" | "format_args_nl") { | 34 | if !matches!(name.text(), "format_args" | "format_args_nl") { |
diff --git a/crates/ide/src/syntax_tree.rs b/crates/ide/src/syntax_tree.rs index f979ba434..8979de528 100644 --- a/crates/ide/src/syntax_tree.rs +++ b/crates/ide/src/syntax_tree.rs | |||
@@ -27,7 +27,7 @@ pub(crate) fn syntax_tree( | |||
27 | if let Some(tree) = syntax_tree_for_string(&token, text_range) { | 27 | if let Some(tree) = syntax_tree_for_string(&token, text_range) { |
28 | return tree; | 28 | return tree; |
29 | } | 29 | } |
30 | token.parent() | 30 | token.parent().unwrap() |
31 | } | 31 | } |
32 | }; | 32 | }; |
33 | 33 | ||
diff --git a/crates/ide/src/typing.rs b/crates/ide/src/typing.rs index a718faf63..e10b7d98e 100644 --- a/crates/ide/src/typing.rs +++ b/crates/ide/src/typing.rs | |||
@@ -108,7 +108,7 @@ fn on_dot_typed(file: &SourceFile, offset: TextSize) -> Option<TextEdit> { | |||
108 | }; | 108 | }; |
109 | let current_indent_len = TextSize::of(current_indent); | 109 | let current_indent_len = TextSize::of(current_indent); |
110 | 110 | ||
111 | let parent = whitespace.syntax().parent(); | 111 | let parent = whitespace.syntax().parent()?; |
112 | // Make sure dot is a part of call chain | 112 | // Make sure dot is a part of call chain |
113 | if !matches!(parent.kind(), FIELD_EXPR | METHOD_CALL_EXPR) { | 113 | if !matches!(parent.kind(), FIELD_EXPR | METHOD_CALL_EXPR) { |
114 | return None; | 114 | return None; |