aboutsummaryrefslogtreecommitdiff
path: root/crates/ide/src
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ide/src')
-rw-r--r--crates/ide/src/call_hierarchy.rs11
-rw-r--r--crates/ide/src/display.rs4
-rw-r--r--crates/ide/src/display/navigation_target.rs44
-rw-r--r--crates/ide/src/display/short_label.rs128
-rw-r--r--crates/ide/src/doc_links.rs2
-rw-r--r--crates/ide/src/extend_selection.rs13
-rw-r--r--crates/ide/src/goto_definition.rs4
-rw-r--r--crates/ide/src/goto_type_definition.rs2
-rw-r--r--crates/ide/src/hover.rs188
-rw-r--r--crates/ide/src/join_lines.rs44
-rw-r--r--crates/ide/src/matching_brace.rs2
-rw-r--r--crates/ide/src/references.rs30
-rw-r--r--crates/ide/src/runnables.rs3
-rw-r--r--crates/ide/src/syntax_highlighting.rs19
-rw-r--r--crates/ide/src/syntax_highlighting/format.rs2
-rw-r--r--crates/ide/src/syntax_tree.rs2
-rw-r--r--crates/ide/src/typing.rs2
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
4pub(crate) mod navigation_target; 4pub(crate) mod navigation_target;
5mod short_label;
6 5
7pub(crate) use navigation_target::{ToNav, TryToNav}; 6pub(crate) use navigation_target::{ToNav, TryToNav};
8pub(crate) use short_label::ShortLabel;
9 7
10pub(crate) use syntax::display::{function_declaration, macro_label}; 8pub(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 @@
3use std::fmt; 3use std::fmt;
4 4
5use either::Either; 5use either::Either;
6use hir::{AssocItem, Documentation, FieldSource, HasAttrs, HasSource, InFile, ModuleSource}; 6use hir::{
7 AssocItem, Documentation, FieldSource, HasAttrs, HasSource, HirDisplay, InFile, ModuleSource,
8 Semantics,
9};
7use ide_db::{ 10use 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
18use crate::FileSymbol; 21use crate::FileSymbol;
19 22
20use 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
252impl<D> TryToNav for D 253impl<D> TryToNav for D
253where 254where
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`
502pub(crate) fn description_from_symbol(db: &RootDatabase, symbol: &FileSymbol) -> Option<String> { 503pub(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
3use stdx::format_to;
4use syntax::ast::{self, AstNode, NameOwner, VisibilityOwner};
5
6pub(crate) trait ShortLabel {
7 fn short_label(&self) -> Option<String>;
8}
9
10impl ShortLabel for ast::Fn {
11 fn short_label(&self) -> Option<String> {
12 Some(crate::display::function_declaration(self))
13 }
14}
15
16impl ShortLabel for ast::Struct {
17 fn short_label(&self) -> Option<String> {
18 short_label_from_node(self, "struct ")
19 }
20}
21
22impl ShortLabel for ast::Union {
23 fn short_label(&self) -> Option<String> {
24 short_label_from_node(self, "union ")
25 }
26}
27
28impl ShortLabel for ast::Enum {
29 fn short_label(&self) -> Option<String> {
30 short_label_from_node(self, "enum ")
31 }
32}
33
34impl 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
44impl ShortLabel for ast::Module {
45 fn short_label(&self) -> Option<String> {
46 short_label_from_node(self, "mod ")
47 }
48}
49
50impl ShortLabel for ast::SourceFile {
51 fn short_label(&self) -> Option<String> {
52 None
53 }
54}
55
56impl ShortLabel for ast::BlockExpr {
57 fn short_label(&self) -> Option<String> {
58 None
59 }
60}
61
62impl 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
72impl ShortLabel for ast::Const {
73 fn short_label(&self) -> Option<String> {
74 short_label_from_ty(self, self.ty(), "const ")
75 }
76}
77
78impl ShortLabel for ast::Static {
79 fn short_label(&self) -> Option<String> {
80 short_label_from_ty(self, self.ty(), "static ")
81 }
82}
83
84impl ShortLabel for ast::RecordField {
85 fn short_label(&self) -> Option<String> {
86 short_label_from_ty(self, self.ty(), "")
87 }
88}
89
90impl ShortLabel for ast::Variant {
91 fn short_label(&self) -> Option<String> {
92 Some(self.name()?.text().to_string())
93 }
94}
95
96impl 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
107fn short_label_from_ty<T>(node: &T, ty: Option<ast::Type>, prefix: &str) -> Option<String>
108where
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
120fn short_label_from_node<T>(node: &T, label: &str) -> Option<String>
121where
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 @@
1use either::Either; 1use either::Either;
2use hir::{ 2use 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};
6use ide_db::{ 6use ide_db::{
7 base_db::SourceDatabase, 7 base_db::SourceDatabase,
@@ -14,7 +14,7 @@ use stdx::format_to;
14use syntax::{ast, match_ast, AstNode, SyntaxKind::*, SyntaxToken, TokenAtOffset, T}; 14use syntax::{ast, match_ast, AstNode, SyntaxKind::*, SyntaxToken, TokenAtOffset, T};
15 15
16use crate::{ 16use 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#"
3666struct S<'a, T>(&'a T);
3667trait Clone {}
3668macro_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
3677foo!();
3678
3679fn 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
47fn 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
58fn remove_newline(edit: &mut TextEditBuilder, token: &SyntaxToken, offset: TextSize) { 64fn 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
150fn join_single_expr_block(edit: &mut TextEditBuilder, token: &SyntaxToken) -> Option<()> { 156fn 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
172fn join_single_use_tree(edit: &mut TextEditBuilder, token: &SyntaxToken) -> Option<()> { 178fn 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
149fn get_name_of_item_declaration(syntax: &SyntaxNode, position: FilePosition) -> Option<ast::Name> { 149fn 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
1280pub struct Fo$0o;
1281//- /level2.rs new_source_root: crate:level2 deps:level3
1282pub use level3::Foo;
1283//- /level1.rs new_source_root: crate:level1 deps:level2
1284pub use level2::Foo;
1285//- /level0.rs new_source_root: crate:level0 deps:level1
1286pub 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
30fn is_format_string(string: &ast::String) -> Option<()> { 30fn 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;