diff options
Diffstat (limited to 'crates/ide/src')
-rw-r--r-- | crates/ide/src/call_hierarchy.rs | 11 | ||||
-rw-r--r-- | crates/ide/src/display.rs | 4 | ||||
-rw-r--r-- | crates/ide/src/display/navigation_target.rs | 44 | ||||
-rw-r--r-- | crates/ide/src/display/short_label.rs | 128 | ||||
-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 | 188 | ||||
-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/references.rs | 30 | ||||
-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, 224 insertions, 276 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..71e97d6b4 100644 --- a/crates/ide/src/display.rs +++ b/crates/ide/src/display.rs | |||
@@ -2,9 +2,7 @@ | |||
2 | //! into types that may be used to render in a UI. | 2 | //! into types that may be used to render in a UI. |
3 | 3 | ||
4 | pub(crate) mod navigation_target; | 4 | pub(crate) mod navigation_target; |
5 | mod short_label; | ||
6 | 5 | ||
7 | pub(crate) use navigation_target::{ToNav, TryToNav}; | 6 | pub(crate) use navigation_target::{ToNav, TryToNav}; |
8 | pub(crate) use short_label::ShortLabel; | ||
9 | 7 | ||
10 | pub(crate) use syntax::display::{function_declaration, macro_label}; | 8 | pub(crate) use syntax::display::macro_label; |
diff --git a/crates/ide/src/display/navigation_target.rs b/crates/ide/src/display/navigation_target.rs index 198243466..c086de163 100644 --- a/crates/ide/src/display/navigation_target.rs +++ b/crates/ide/src/display/navigation_target.rs | |||
@@ -3,9 +3,12 @@ | |||
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 | Semantics, | ||
9 | }; | ||
7 | use ide_db::{ | 10 | use ide_db::{ |
8 | base_db::{FileId, FileRange, SourceDatabase}, | 11 | base_db::{FileId, FileRange}, |
9 | symbol_index::FileSymbolKind, | 12 | symbol_index::FileSymbolKind, |
10 | SymbolKind, | 13 | SymbolKind, |
11 | }; | 14 | }; |
@@ -17,8 +20,6 @@ use syntax::{ | |||
17 | 20 | ||
18 | use crate::FileSymbol; | 21 | use crate::FileSymbol; |
19 | 22 | ||
20 | use super::short_label::ShortLabel; | ||
21 | |||
22 | /// `NavigationTarget` represents and element in the editor's UI which you can | 23 | /// `NavigationTarget` represents and element in the editor's UI which you can |
23 | /// click on to navigate to a particular piece of code. | 24 | /// click on to navigate to a particular piece of code. |
24 | /// | 25 | /// |
@@ -98,7 +99,7 @@ impl NavigationTarget { | |||
98 | SymbolKind::Module, | 99 | SymbolKind::Module, |
99 | ); | 100 | ); |
100 | res.docs = module.attrs(db).docs(); | 101 | res.docs = module.attrs(db).docs(); |
101 | res.description = src.value.short_label(); | 102 | res.description = Some(module.display(db).to_string()); |
102 | return res; | 103 | return res; |
103 | } | 104 | } |
104 | module.to_nav(db) | 105 | module.to_nav(db) |
@@ -251,8 +252,8 @@ impl ToNavFromAst for hir::Trait { | |||
251 | 252 | ||
252 | impl<D> TryToNav for D | 253 | impl<D> TryToNav for D |
253 | where | 254 | where |
254 | D: HasSource + ToNavFromAst + Copy + HasAttrs, | 255 | D: HasSource + ToNavFromAst + Copy + HasAttrs + HirDisplay, |
255 | D::Ast: ast::NameOwner + ShortLabel, | 256 | D::Ast: ast::NameOwner, |
256 | { | 257 | { |
257 | fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> { | 258 | fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> { |
258 | let src = self.source(db)?; | 259 | let src = self.source(db)?; |
@@ -262,7 +263,7 @@ where | |||
262 | D::KIND, | 263 | D::KIND, |
263 | ); | 264 | ); |
264 | res.docs = self.docs(db); | 265 | res.docs = self.docs(db); |
265 | res.description = src.value.short_label(); | 266 | res.description = Some(self.display(db).to_string()); |
266 | Some(res) | 267 | Some(res) |
267 | } | 268 | } |
268 | } | 269 | } |
@@ -317,7 +318,7 @@ impl TryToNav for hir::Field { | |||
317 | let mut res = | 318 | let mut res = |
318 | NavigationTarget::from_named(db, src.with_value(it), SymbolKind::Field); | 319 | NavigationTarget::from_named(db, src.with_value(it), SymbolKind::Field); |
319 | res.docs = self.docs(db); | 320 | res.docs = self.docs(db); |
320 | res.description = it.short_label(); | 321 | res.description = Some(self.display(db).to_string()); |
321 | res | 322 | res |
322 | } | 323 | } |
323 | FieldSource::Pos(it) => { | 324 | FieldSource::Pos(it) => { |
@@ -500,21 +501,22 @@ impl TryToNav for hir::ConstParam { | |||
500 | /// | 501 | /// |
501 | /// e.g. `struct Name`, `enum Name`, `fn Name` | 502 | /// e.g. `struct Name`, `enum Name`, `fn Name` |
502 | pub(crate) fn description_from_symbol(db: &RootDatabase, symbol: &FileSymbol) -> Option<String> { | 503 | pub(crate) fn description_from_symbol(db: &RootDatabase, symbol: &FileSymbol) -> Option<String> { |
503 | let parse = db.parse(symbol.file_id); | 504 | let sema = Semantics::new(db); |
504 | let node = symbol.ptr.to_node(parse.tree().syntax()); | 505 | let parse = sema.parse(symbol.file_id); |
506 | let node = symbol.ptr.to_node(parse.syntax()); | ||
505 | 507 | ||
506 | match_ast! { | 508 | match_ast! { |
507 | match node { | 509 | match node { |
508 | ast::Fn(it) => it.short_label(), | 510 | ast::Fn(it) => sema.to_def(&it).map(|it| it.display(db).to_string()), |
509 | ast::Struct(it) => it.short_label(), | 511 | ast::Struct(it) => sema.to_def(&it).map(|it| it.display(db).to_string()), |
510 | ast::Enum(it) => it.short_label(), | 512 | ast::Enum(it) => sema.to_def(&it).map(|it| it.display(db).to_string()), |
511 | ast::Trait(it) => it.short_label(), | 513 | ast::Trait(it) => sema.to_def(&it).map(|it| it.display(db).to_string()), |
512 | ast::Module(it) => it.short_label(), | 514 | ast::Module(it) => sema.to_def(&it).map(|it| it.display(db).to_string()), |
513 | ast::TypeAlias(it) => it.short_label(), | 515 | ast::TypeAlias(it) => sema.to_def(&it).map(|it| it.display(db).to_string()), |
514 | ast::Const(it) => it.short_label(), | 516 | ast::Const(it) => sema.to_def(&it).map(|it| it.display(db).to_string()), |
515 | ast::Static(it) => it.short_label(), | 517 | ast::Static(it) => sema.to_def(&it).map(|it| it.display(db).to_string()), |
516 | ast::RecordField(it) => it.short_label(), | 518 | ast::RecordField(it) => sema.to_def(&it).map(|it| it.display(db).to_string()), |
517 | ast::Variant(it) => it.short_label(), | 519 | ast::Variant(it) => sema.to_def(&it).map(|it| it.display(db).to_string()), |
518 | _ => None, | 520 | _ => None, |
519 | } | 521 | } |
520 | } | 522 | } |
diff --git a/crates/ide/src/display/short_label.rs b/crates/ide/src/display/short_label.rs deleted file mode 100644 index 2df9266b4..000000000 --- a/crates/ide/src/display/short_label.rs +++ /dev/null | |||
@@ -1,128 +0,0 @@ | |||
1 | //! FIXME: write short doc here | ||
2 | |||
3 | use stdx::format_to; | ||
4 | use syntax::ast::{self, AstNode, NameOwner, VisibilityOwner}; | ||
5 | |||
6 | pub(crate) trait ShortLabel { | ||
7 | fn short_label(&self) -> Option<String>; | ||
8 | } | ||
9 | |||
10 | impl ShortLabel for ast::Fn { | ||
11 | fn short_label(&self) -> Option<String> { | ||
12 | Some(crate::display::function_declaration(self)) | ||
13 | } | ||
14 | } | ||
15 | |||
16 | impl ShortLabel for ast::Struct { | ||
17 | fn short_label(&self) -> Option<String> { | ||
18 | short_label_from_node(self, "struct ") | ||
19 | } | ||
20 | } | ||
21 | |||
22 | impl ShortLabel for ast::Union { | ||
23 | fn short_label(&self) -> Option<String> { | ||
24 | short_label_from_node(self, "union ") | ||
25 | } | ||
26 | } | ||
27 | |||
28 | impl ShortLabel for ast::Enum { | ||
29 | fn short_label(&self) -> Option<String> { | ||
30 | short_label_from_node(self, "enum ") | ||
31 | } | ||
32 | } | ||
33 | |||
34 | impl ShortLabel for ast::Trait { | ||
35 | fn short_label(&self) -> Option<String> { | ||
36 | if self.unsafe_token().is_some() { | ||
37 | short_label_from_node(self, "unsafe trait ") | ||
38 | } else { | ||
39 | short_label_from_node(self, "trait ") | ||
40 | } | ||
41 | } | ||
42 | } | ||
43 | |||
44 | impl ShortLabel for ast::Module { | ||
45 | fn short_label(&self) -> Option<String> { | ||
46 | short_label_from_node(self, "mod ") | ||
47 | } | ||
48 | } | ||
49 | |||
50 | impl ShortLabel for ast::SourceFile { | ||
51 | fn short_label(&self) -> Option<String> { | ||
52 | None | ||
53 | } | ||
54 | } | ||
55 | |||
56 | impl ShortLabel for ast::BlockExpr { | ||
57 | fn short_label(&self) -> Option<String> { | ||
58 | None | ||
59 | } | ||
60 | } | ||
61 | |||
62 | impl ShortLabel for ast::TypeAlias { | ||
63 | fn short_label(&self) -> Option<String> { | ||
64 | let mut buf = short_label_from_node(self, "type ")?; | ||
65 | if let Some(type_ref) = self.ty() { | ||
66 | format_to!(buf, " = {}", type_ref.syntax()); | ||
67 | } | ||
68 | Some(buf) | ||
69 | } | ||
70 | } | ||
71 | |||
72 | impl ShortLabel for ast::Const { | ||
73 | fn short_label(&self) -> Option<String> { | ||
74 | short_label_from_ty(self, self.ty(), "const ") | ||
75 | } | ||
76 | } | ||
77 | |||
78 | impl ShortLabel for ast::Static { | ||
79 | fn short_label(&self) -> Option<String> { | ||
80 | short_label_from_ty(self, self.ty(), "static ") | ||
81 | } | ||
82 | } | ||
83 | |||
84 | impl ShortLabel for ast::RecordField { | ||
85 | fn short_label(&self) -> Option<String> { | ||
86 | short_label_from_ty(self, self.ty(), "") | ||
87 | } | ||
88 | } | ||
89 | |||
90 | impl ShortLabel for ast::Variant { | ||
91 | fn short_label(&self) -> Option<String> { | ||
92 | Some(self.name()?.text().to_string()) | ||
93 | } | ||
94 | } | ||
95 | |||
96 | impl ShortLabel for ast::ConstParam { | ||
97 | fn short_label(&self) -> Option<String> { | ||
98 | let mut buf = "const ".to_owned(); | ||
99 | buf.push_str(self.name()?.text()); | ||
100 | if let Some(type_ref) = self.ty() { | ||
101 | format_to!(buf, ": {}", type_ref.syntax()); | ||
102 | } | ||
103 | Some(buf) | ||
104 | } | ||
105 | } | ||
106 | |||
107 | fn short_label_from_ty<T>(node: &T, ty: Option<ast::Type>, prefix: &str) -> Option<String> | ||
108 | where | ||
109 | T: NameOwner + VisibilityOwner, | ||
110 | { | ||
111 | let mut buf = short_label_from_node(node, prefix)?; | ||
112 | |||
113 | if let Some(type_ref) = ty { | ||
114 | format_to!(buf, ": {}", type_ref.syntax()); | ||
115 | } | ||
116 | |||
117 | Some(buf) | ||
118 | } | ||
119 | |||
120 | fn short_label_from_node<T>(node: &T, label: &str) -> Option<String> | ||
121 | where | ||
122 | T: NameOwner + VisibilityOwner, | ||
123 | { | ||
124 | let mut buf = node.visibility().map(|v| format!("{} ", v.syntax())).unwrap_or_default(); | ||
125 | buf.push_str(label); | ||
126 | buf.push_str(node.name()?.text()); | ||
127 | Some(buf) | ||
128 | } | ||
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..325014622 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 | 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,61 +335,34 @@ 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(it) => from_hir_fmt(db, it, mod_path), |
350 | match it.definition_source(db).value { | 343 | ModuleDef::Variant(it) => from_hir_fmt(db, it, mod_path), |
351 | ModuleSource::Module(it) => it.short_label(), | 344 | ModuleDef::Const(it) => from_hir_fmt(db, it, mod_path), |
352 | ModuleSource::SourceFile(it) => it.short_label(), | 345 | ModuleDef::Static(it) => from_hir_fmt(db, it, mod_path), |
353 | ModuleSource::BlockExpr(it) => it.short_label(), | 346 | ModuleDef::Trait(it) => from_hir_fmt(db, it, mod_path), |
354 | }, | 347 | ModuleDef::TypeAlias(it) => from_hir_fmt(db, it, mod_path), |
355 | mod_path, | ||
356 | ), | ||
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 | 348 | ModuleDef::BuiltinType(it) => famous_defs |
367 | .and_then(|fd| hover_for_builtin(fd, it)) | 349 | .and_then(|fd| hover_for_builtin(fd, it)) |
368 | .or_else(|| Some(Markup::fenced_block(&it.name()))), | 350 | .or_else(|| Some(Markup::fenced_block(&it.name()))), |
369 | }, | 351 | }, |
370 | Definition::Local(it) => hover_for_local(it, db), | 352 | Definition::Local(it) => hover_for_local(it, db), |
371 | Definition::SelfType(impl_def) => { | 353 | Definition::SelfType(impl_def) => { |
372 | impl_def.target_ty(db).as_adt().and_then(|adt| match adt { | 354 | impl_def.target_ty(db).as_adt().and_then(|adt| from_hir_fmt(db, adt, mod_path)) |
373 | Adt::Struct(it) => from_def_source(db, it, mod_path), | ||
374 | Adt::Union(it) => from_def_source(db, it, mod_path), | ||
375 | Adt::Enum(it) => from_def_source(db, it, mod_path), | ||
376 | }) | ||
377 | } | 355 | } |
356 | Definition::GenericParam(it) => from_hir_fmt(db, it, None), | ||
378 | Definition::Label(it) => Some(Markup::fenced_block(&it.name(db))), | 357 | Definition::Label(it) => Some(Markup::fenced_block(&it.name(db))), |
379 | Definition::GenericParam(it) => match it { | ||
380 | GenericParam::TypeParam(it) => Some(Markup::fenced_block(&it.display(db))), | ||
381 | GenericParam::LifetimeParam(it) => Some(Markup::fenced_block(&it.name(db))), | ||
382 | GenericParam::ConstParam(it) => from_def_source(db, it, None), | ||
383 | }, | ||
384 | }; | 358 | }; |
385 | 359 | ||
386 | fn from_def_source<A, D>(db: &RootDatabase, def: D, mod_path: Option<String>) -> Option<Markup> | 360 | fn from_hir_fmt<D>(db: &RootDatabase, def: D, mod_path: Option<String>) -> Option<Markup> |
387 | where | 361 | where |
388 | D: HasSource<Ast = A> + HasAttrs + Copy, | 362 | D: HasAttrs + HirDisplay, |
389 | A: ShortLabel, | ||
390 | { | 363 | { |
391 | let short_label = def.source(db)?.value.short_label(); | 364 | let label = def.display(db).to_string(); |
392 | from_def_source_labeled(db, def, short_label, mod_path) | 365 | from_def_source_labeled(db, def, Some(label), mod_path) |
393 | } | 366 | } |
394 | 367 | ||
395 | fn from_def_source_labeled<D>( | 368 | fn from_def_source_labeled<D>( |
@@ -438,7 +411,7 @@ fn hover_for_keyword( | |||
438 | if !token.kind().is_keyword() { | 411 | if !token.kind().is_keyword() { |
439 | return None; | 412 | return None; |
440 | } | 413 | } |
441 | let famous_defs = FamousDefs(&sema, sema.scope(&token.parent()).krate()); | 414 | let famous_defs = FamousDefs(&sema, sema.scope(&token.parent()?).krate()); |
442 | // std exposes {}_keyword modules with docstrings on the root to document keywords | 415 | // std exposes {}_keyword modules with docstrings on the root to document keywords |
443 | let keyword_mod = format!("{}_keyword", token.text()); | 416 | let keyword_mod = format!("{}_keyword", token.text()); |
444 | let doc_owner = find_std_module(&famous_defs, &keyword_mod)?; | 417 | let doc_owner = find_std_module(&famous_defs, &keyword_mod)?; |
@@ -670,7 +643,9 @@ fn main() { let foo_test = fo$0o(); } | |||
670 | ``` | 643 | ``` |
671 | 644 | ||
672 | ```rust | 645 | ```rust |
673 | pub fn foo<'a, T: AsRef<str>>(b: &'a T) -> &'a str | 646 | pub fn foo<'a, T>(b: &'a T) -> &'a str |
647 | where | ||
648 | T: AsRef<str>, | ||
674 | ``` | 649 | ``` |
675 | "#]], | 650 | "#]], |
676 | ); | 651 | ); |
@@ -878,7 +853,7 @@ fn main() { So$0me(12); } | |||
878 | ``` | 853 | ``` |
879 | 854 | ||
880 | ```rust | 855 | ```rust |
881 | Some | 856 | Some(T) |
882 | ``` | 857 | ``` |
883 | "#]], | 858 | "#]], |
884 | ); | 859 | ); |
@@ -944,7 +919,7 @@ fn main() { | |||
944 | ``` | 919 | ``` |
945 | 920 | ||
946 | ```rust | 921 | ```rust |
947 | Some | 922 | Some(T) |
948 | ``` | 923 | ``` |
949 | 924 | ||
950 | --- | 925 | --- |
@@ -1441,13 +1416,14 @@ fn bar() { fo$0o(); } | |||
1441 | ``` | 1416 | ``` |
1442 | "#]], | 1417 | "#]], |
1443 | ); | 1418 | ); |
1419 | // Top level `pub(crate)` will be displayed as no visibility. | ||
1444 | check( | 1420 | check( |
1445 | r#"pub(crate) async unsafe extern "C" fn foo$0() {}"#, | 1421 | r#"mod m { pub(crate) async unsafe extern "C" fn foo$0() {} }"#, |
1446 | expect![[r#" | 1422 | expect![[r#" |
1447 | *foo* | 1423 | *foo* |
1448 | 1424 | ||
1449 | ```rust | 1425 | ```rust |
1450 | test | 1426 | test::m |
1451 | ``` | 1427 | ``` |
1452 | 1428 | ||
1453 | ```rust | 1429 | ```rust |
@@ -1489,11 +1465,18 @@ extern crate st$0d; | |||
1489 | //! abc123 | 1465 | //! abc123 |
1490 | "#, | 1466 | "#, |
1491 | expect![[r#" | 1467 | expect![[r#" |
1492 | *std* | 1468 | *std* |
1493 | Standard library for this test | 1469 | |
1470 | ```rust | ||
1471 | extern crate std | ||
1472 | ``` | ||
1473 | |||
1474 | --- | ||
1494 | 1475 | ||
1495 | Printed? | 1476 | Standard library for this test |
1496 | abc123 | 1477 | |
1478 | Printed? | ||
1479 | abc123 | ||
1497 | "#]], | 1480 | "#]], |
1498 | ); | 1481 | ); |
1499 | check( | 1482 | check( |
@@ -1507,11 +1490,18 @@ extern crate std as ab$0c; | |||
1507 | //! abc123 | 1490 | //! abc123 |
1508 | "#, | 1491 | "#, |
1509 | expect![[r#" | 1492 | expect![[r#" |
1510 | *abc* | 1493 | *abc* |
1511 | Standard library for this test | 1494 | |
1495 | ```rust | ||
1496 | extern crate std | ||
1497 | ``` | ||
1512 | 1498 | ||
1513 | Printed? | 1499 | --- |
1514 | abc123 | 1500 | |
1501 | Standard library for this test | ||
1502 | |||
1503 | Printed? | ||
1504 | abc123 | ||
1515 | "#]], | 1505 | "#]], |
1516 | ); | 1506 | ); |
1517 | } | 1507 | } |
@@ -2021,7 +2011,7 @@ enum E { | |||
2021 | ``` | 2011 | ``` |
2022 | 2012 | ||
2023 | ```rust | 2013 | ```rust |
2024 | V | 2014 | V { field: i32 } |
2025 | ``` | 2015 | ``` |
2026 | 2016 | ||
2027 | --- | 2017 | --- |
@@ -2417,7 +2407,7 @@ fn main() { let s$0t = S{ f1:Arg(0) }; } | |||
2417 | focus_range: 24..25, | 2407 | focus_range: 24..25, |
2418 | name: "S", | 2408 | name: "S", |
2419 | kind: Struct, | 2409 | kind: Struct, |
2420 | description: "struct S", | 2410 | description: "struct S<T>", |
2421 | }, | 2411 | }, |
2422 | }, | 2412 | }, |
2423 | HoverGotoTypeData { | 2413 | HoverGotoTypeData { |
@@ -2463,7 +2453,7 @@ fn main() { let s$0t = S{ f1: S{ f1: Arg(0) } }; } | |||
2463 | focus_range: 24..25, | 2453 | focus_range: 24..25, |
2464 | name: "S", | 2454 | name: "S", |
2465 | kind: Struct, | 2455 | kind: Struct, |
2466 | description: "struct S", | 2456 | description: "struct S<T>", |
2467 | }, | 2457 | }, |
2468 | }, | 2458 | }, |
2469 | HoverGotoTypeData { | 2459 | HoverGotoTypeData { |
@@ -2605,7 +2595,7 @@ fn main() { let s$0t = foo(); } | |||
2605 | focus_range: 6..9, | 2595 | focus_range: 6..9, |
2606 | name: "Foo", | 2596 | name: "Foo", |
2607 | kind: Trait, | 2597 | kind: Trait, |
2608 | description: "trait Foo", | 2598 | description: "trait Foo<T>", |
2609 | }, | 2599 | }, |
2610 | }, | 2600 | }, |
2611 | HoverGotoTypeData { | 2601 | HoverGotoTypeData { |
@@ -2702,7 +2692,7 @@ fn main() { let s$0t = foo(); } | |||
2702 | focus_range: 6..9, | 2692 | focus_range: 6..9, |
2703 | name: "Foo", | 2693 | name: "Foo", |
2704 | kind: Trait, | 2694 | kind: Trait, |
2705 | description: "trait Foo", | 2695 | description: "trait Foo<T>", |
2706 | }, | 2696 | }, |
2707 | }, | 2697 | }, |
2708 | HoverGotoTypeData { | 2698 | HoverGotoTypeData { |
@@ -2715,7 +2705,7 @@ fn main() { let s$0t = foo(); } | |||
2715 | focus_range: 22..25, | 2705 | focus_range: 22..25, |
2716 | name: "Bar", | 2706 | name: "Bar", |
2717 | kind: Trait, | 2707 | kind: Trait, |
2718 | description: "trait Bar", | 2708 | description: "trait Bar<T>", |
2719 | }, | 2709 | }, |
2720 | }, | 2710 | }, |
2721 | HoverGotoTypeData { | 2711 | HoverGotoTypeData { |
@@ -2819,7 +2809,7 @@ fn foo(ar$0g: &impl Foo + Bar<S>) {} | |||
2819 | focus_range: 19..22, | 2809 | focus_range: 19..22, |
2820 | name: "Bar", | 2810 | name: "Bar", |
2821 | kind: Trait, | 2811 | kind: Trait, |
2822 | description: "trait Bar", | 2812 | description: "trait Bar<T>", |
2823 | }, | 2813 | }, |
2824 | }, | 2814 | }, |
2825 | HoverGotoTypeData { | 2815 | HoverGotoTypeData { |
@@ -2916,7 +2906,7 @@ fn foo(ar$0g: &impl Foo<S>) {} | |||
2916 | focus_range: 6..9, | 2906 | focus_range: 6..9, |
2917 | name: "Foo", | 2907 | name: "Foo", |
2918 | kind: Trait, | 2908 | kind: Trait, |
2919 | description: "trait Foo", | 2909 | description: "trait Foo<T>", |
2920 | }, | 2910 | }, |
2921 | }, | 2911 | }, |
2922 | HoverGotoTypeData { | 2912 | HoverGotoTypeData { |
@@ -2966,7 +2956,7 @@ fn main() { let s$0t = foo(); } | |||
2966 | focus_range: 49..50, | 2956 | focus_range: 49..50, |
2967 | name: "B", | 2957 | name: "B", |
2968 | kind: Struct, | 2958 | kind: Struct, |
2969 | description: "struct B", | 2959 | description: "struct B<T>", |
2970 | }, | 2960 | }, |
2971 | }, | 2961 | }, |
2972 | HoverGotoTypeData { | 2962 | HoverGotoTypeData { |
@@ -3042,7 +3032,7 @@ fn foo(ar$0g: &dyn Foo<S>) {} | |||
3042 | focus_range: 6..9, | 3032 | focus_range: 6..9, |
3043 | name: "Foo", | 3033 | name: "Foo", |
3044 | kind: Trait, | 3034 | kind: Trait, |
3045 | description: "trait Foo", | 3035 | description: "trait Foo<T>", |
3046 | }, | 3036 | }, |
3047 | }, | 3037 | }, |
3048 | HoverGotoTypeData { | 3038 | HoverGotoTypeData { |
@@ -3090,7 +3080,7 @@ fn foo(a$0rg: &impl ImplTrait<B<dyn DynTrait<B<S>>>>) {} | |||
3090 | focus_range: 6..15, | 3080 | focus_range: 6..15, |
3091 | name: "ImplTrait", | 3081 | name: "ImplTrait", |
3092 | kind: Trait, | 3082 | kind: Trait, |
3093 | description: "trait ImplTrait", | 3083 | description: "trait ImplTrait<T>", |
3094 | }, | 3084 | }, |
3095 | }, | 3085 | }, |
3096 | HoverGotoTypeData { | 3086 | HoverGotoTypeData { |
@@ -3103,7 +3093,7 @@ fn foo(a$0rg: &impl ImplTrait<B<dyn DynTrait<B<S>>>>) {} | |||
3103 | focus_range: 50..51, | 3093 | focus_range: 50..51, |
3104 | name: "B", | 3094 | name: "B", |
3105 | kind: Struct, | 3095 | kind: Struct, |
3106 | description: "struct B", | 3096 | description: "struct B<T>", |
3107 | }, | 3097 | }, |
3108 | }, | 3098 | }, |
3109 | HoverGotoTypeData { | 3099 | HoverGotoTypeData { |
@@ -3116,7 +3106,7 @@ fn foo(a$0rg: &impl ImplTrait<B<dyn DynTrait<B<S>>>>) {} | |||
3116 | focus_range: 28..36, | 3106 | focus_range: 28..36, |
3117 | name: "DynTrait", | 3107 | name: "DynTrait", |
3118 | kind: Trait, | 3108 | kind: Trait, |
3119 | description: "trait DynTrait", | 3109 | description: "trait DynTrait<T>", |
3120 | }, | 3110 | }, |
3121 | }, | 3111 | }, |
3122 | HoverGotoTypeData { | 3112 | HoverGotoTypeData { |
@@ -3582,6 +3572,17 @@ mod foo$0; | |||
3582 | "#, | 3572 | "#, |
3583 | expect![[r#" | 3573 | expect![[r#" |
3584 | *foo* | 3574 | *foo* |
3575 | |||
3576 | ```rust | ||
3577 | test | ||
3578 | ``` | ||
3579 | |||
3580 | ```rust | ||
3581 | mod foo | ||
3582 | ``` | ||
3583 | |||
3584 | --- | ||
3585 | |||
3585 | For the horde! | 3586 | For the horde! |
3586 | "#]], | 3587 | "#]], |
3587 | ); | 3588 | ); |
@@ -3606,7 +3607,7 @@ use foo::bar::{self$0}; | |||
3606 | ``` | 3607 | ``` |
3607 | 3608 | ||
3608 | ```rust | 3609 | ```rust |
3609 | pub mod bar | 3610 | mod bar |
3610 | ``` | 3611 | ``` |
3611 | 3612 | ||
3612 | --- | 3613 | --- |
@@ -3657,4 +3658,43 @@ cosnt _: &str$0 = ""; }"#; | |||
3657 | "#]], | 3658 | "#]], |
3658 | ); | 3659 | ); |
3659 | } | 3660 | } |
3661 | |||
3662 | #[test] | ||
3663 | fn hover_macro_expanded_function() { | ||
3664 | check( | ||
3665 | r#" | ||
3666 | struct S<'a, T>(&'a T); | ||
3667 | trait Clone {} | ||
3668 | macro_rules! foo { | ||
3669 | () => { | ||
3670 | fn bar<'t, T: Clone + 't>(s: &mut S<'t, T>, t: u32) -> *mut u32 where | ||
3671 | 't: 't + 't, | ||
3672 | for<'a> T: Clone + 'a | ||
3673 | { 0 as _ } | ||
3674 | }; | ||
3675 | } | ||
3676 | |||
3677 | foo!(); | ||
3678 | |||
3679 | fn main() { | ||
3680 | bar$0; | ||
3681 | } | ||
3682 | "#, | ||
3683 | expect![[r#" | ||
3684 | *bar* | ||
3685 | |||
3686 | ```rust | ||
3687 | test | ||
3688 | ``` | ||
3689 | |||
3690 | ```rust | ||
3691 | fn bar<'t, T>(s: &mut S<'t, T>, t: u32) -> *mut u32 | ||
3692 | where | ||
3693 | T: Clone + 't, | ||
3694 | 't: 't + 't, | ||
3695 | for<'a> T: Clone + 'a, | ||
3696 | ``` | ||
3697 | "#]], | ||
3698 | ) | ||
3699 | } | ||
3660 | } | 3700 | } |
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/references.rs b/crates/ide/src/references.rs index ec7c7686d..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(), |
@@ -1270,4 +1271,27 @@ fn foo(_: bool) -> bo$0ol { true } | |||
1270 | "#]], | 1271 | "#]], |
1271 | ); | 1272 | ); |
1272 | } | 1273 | } |
1274 | |||
1275 | #[test] | ||
1276 | fn test_transitive() { | ||
1277 | check( | ||
1278 | r#" | ||
1279 | //- /level3.rs new_source_root: crate:level3 | ||
1280 | pub struct Fo$0o; | ||
1281 | //- /level2.rs new_source_root: crate:level2 deps:level3 | ||
1282 | pub use level3::Foo; | ||
1283 | //- /level1.rs new_source_root: crate:level1 deps:level2 | ||
1284 | pub use level2::Foo; | ||
1285 | //- /level0.rs new_source_root: crate:level0 deps:level1 | ||
1286 | pub use level1::Foo; | ||
1287 | "#, | ||
1288 | expect![[r#" | ||
1289 | Foo Struct FileId(0) 0..15 11..14 | ||
1290 | |||
1291 | FileId(1) 16..19 | ||
1292 | FileId(2) 16..19 | ||
1293 | FileId(3) 16..19 | ||
1294 | "#]], | ||
1295 | ); | ||
1296 | } | ||
1273 | } | 1297 | } |
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; |