aboutsummaryrefslogtreecommitdiff
path: root/crates/ide
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ide')
-rw-r--r--crates/ide/src/annotations.rs2
-rw-r--r--crates/ide/src/diagnostics.rs1
-rw-r--r--crates/ide/src/diagnostics/fixes.rs2
-rw-r--r--crates/ide/src/diagnostics/unlinked_file.rs2
-rw-r--r--crates/ide/src/doc_links.rs67
-rw-r--r--crates/ide/src/expand_macro.rs2
-rw-r--r--crates/ide/src/extend_selection.rs2
-rw-r--r--crates/ide/src/file_structure.rs5
-rw-r--r--crates/ide/src/folding_ranges.rs39
-rw-r--r--crates/ide/src/goto_definition.rs17
-rw-r--r--crates/ide/src/goto_implementation.rs2
-rw-r--r--crates/ide/src/goto_type_definition.rs2
-rw-r--r--crates/ide/src/hover.rs40
-rw-r--r--crates/ide/src/inlay_hints.rs4
-rw-r--r--crates/ide/src/join_lines.rs2
-rw-r--r--crates/ide/src/matching_brace.rs2
-rw-r--r--crates/ide/src/move_item.rs271
-rw-r--r--crates/ide/src/parent_module.rs2
-rw-r--r--crates/ide/src/references.rs2
-rw-r--r--crates/ide/src/references/rename.rs4
-rw-r--r--crates/ide/src/runnables.rs3
-rw-r--r--crates/ide/src/status.rs1
-rw-r--r--crates/ide/src/syntax_highlighting.rs28
-rw-r--r--crates/ide/src/syntax_highlighting/format.rs2
-rw-r--r--crates/ide/src/syntax_highlighting/highlight.rs35
-rw-r--r--crates/ide/src/syntax_highlighting/inject.rs35
-rw-r--r--crates/ide/src/syntax_highlighting/macro_.rs (renamed from crates/ide/src/syntax_highlighting/macro_rules.rs)10
-rw-r--r--crates/ide/src/syntax_highlighting/tags.rs4
-rw-r--r--crates/ide/src/syntax_highlighting/test_data/highlight_assoc_functions.html8
-rw-r--r--crates/ide/src/syntax_highlighting/test_data/highlight_injection.html2
-rw-r--r--crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html6
-rw-r--r--crates/ide/src/syntax_highlighting/test_data/highlighting.html16
-rw-r--r--crates/ide/src/syntax_highlighting/tests.rs10
-rw-r--r--crates/ide/src/syntax_tree.rs1
-rw-r--r--crates/ide/src/typing/on_enter.rs2
-rw-r--r--crates/ide/src/view_hir.rs1
36 files changed, 512 insertions, 122 deletions
diff --git a/crates/ide/src/annotations.rs b/crates/ide/src/annotations.rs
index 64bc926f1..5ebe7fd0e 100644
--- a/crates/ide/src/annotations.rs
+++ b/crates/ide/src/annotations.rs
@@ -19,6 +19,8 @@ use crate::{
19// 19//
20// Provides user with annotations above items for looking up references or impl blocks 20// Provides user with annotations above items for looking up references or impl blocks
21// and running/debugging binaries. 21// and running/debugging binaries.
22//
23// image::https://user-images.githubusercontent.com/48062697/113020672-b7c34f00-917a-11eb-8f6e-858735660a0e.png[]
22#[derive(Debug)] 24#[derive(Debug)]
23pub struct Annotation { 25pub struct Annotation {
24 pub range: TextRange, 26 pub range: TextRange,
diff --git a/crates/ide/src/diagnostics.rs b/crates/ide/src/diagnostics.rs
index 22697a537..dd42116a7 100644
--- a/crates/ide/src/diagnostics.rs
+++ b/crates/ide/src/diagnostics.rs
@@ -165,7 +165,6 @@ pub(crate) fn diagnostics(
165 sema.diagnostics_display_range(d.display_source()).range, 165 sema.diagnostics_display_range(d.display_source()).range,
166 d.message(), 166 d.message(),
167 ) 167 )
168 .with_unused(true)
169 .with_fix(d.fix(&sema)) 168 .with_fix(d.fix(&sema))
170 .with_code(Some(d.code())), 169 .with_code(Some(d.code())),
171 ); 170 );
diff --git a/crates/ide/src/diagnostics/fixes.rs b/crates/ide/src/diagnostics/fixes.rs
index 2f840909c..5fb3e2d91 100644
--- a/crates/ide/src/diagnostics/fixes.rs
+++ b/crates/ide/src/diagnostics/fixes.rs
@@ -210,7 +210,7 @@ fn missing_record_expr_field_fix(
210 } 210 }
211 let new_field = make::record_field( 211 let new_field = make::record_field(
212 None, 212 None,
213 make::name(record_expr_field.field_name()?.text()), 213 make::name(&record_expr_field.field_name()?.text()),
214 make::ty(&new_field_type.display_source_code(sema.db, module.into()).ok()?), 214 make::ty(&new_field_type.display_source_code(sema.db, module.into()).ok()?),
215 ); 215 );
216 216
diff --git a/crates/ide/src/diagnostics/unlinked_file.rs b/crates/ide/src/diagnostics/unlinked_file.rs
index 019b0b440..e174fb767 100644
--- a/crates/ide/src/diagnostics/unlinked_file.rs
+++ b/crates/ide/src/diagnostics/unlinked_file.rs
@@ -63,7 +63,7 @@ impl DiagnosticWithFix for UnlinkedFile {
63 // - `$dir.rs` in the parent folder, where `$dir` is the directory containing `self.file_id` 63 // - `$dir.rs` in the parent folder, where `$dir` is the directory containing `self.file_id`
64 let parent = our_path.parent()?; 64 let parent = our_path.parent()?;
65 let mut paths = 65 let mut paths =
66 vec![parent.join("mod.rs")?, parent.join("main.rs")?, parent.join("lib.rs")?]; 66 vec![parent.join("mod.rs")?, parent.join("lib.rs")?, parent.join("main.rs")?];
67 67
68 // `submod/bla.rs` -> `submod.rs` 68 // `submod/bla.rs` -> `submod.rs`
69 if let Some(newmod) = (|| { 69 if let Some(newmod) = (|| {
diff --git a/crates/ide/src/doc_links.rs b/crates/ide/src/doc_links.rs
index 0cee741ac..67e2e5a1c 100644
--- a/crates/ide/src/doc_links.rs
+++ b/crates/ide/src/doc_links.rs
@@ -98,6 +98,29 @@ pub(crate) fn remove_links(markdown: &str) -> String {
98 out 98 out
99} 99}
100 100
101/// Retrieve a link to documentation for the given symbol.
102pub(crate) fn external_docs(
103 db: &RootDatabase,
104 position: &FilePosition,
105) -> Option<DocumentationLink> {
106 let sema = Semantics::new(db);
107 let file = sema.parse(position.file_id).syntax().clone();
108 let token = pick_best(file.token_at_offset(position.offset))?;
109 let token = sema.descend_into_macros(token);
110
111 let node = token.parent()?;
112 let definition = match_ast! {
113 match node {
114 ast::NameRef(name_ref) => NameRefClass::classify(&sema, &name_ref).map(|d| d.referenced(sema.db)),
115 ast::Name(name) => NameClass::classify(&sema, &name).map(|d| d.referenced_or_defined(sema.db)),
116 _ => None,
117 }
118 };
119
120 get_doc_link(db, definition?)
121}
122
123/// Extracts all links from a given markdown text.
101pub(crate) fn extract_definitions_from_markdown( 124pub(crate) fn extract_definitions_from_markdown(
102 markdown: &str, 125 markdown: &str,
103) -> Vec<(Range<usize>, String, Option<hir::Namespace>)> { 126) -> Vec<(Range<usize>, String, Option<hir::Namespace>)> {
@@ -161,7 +184,7 @@ pub(crate) fn doc_owner_to_def(
161 ast::Variant(it) => sema.to_def(&it)?.into(), 184 ast::Variant(it) => sema.to_def(&it)?.into(),
162 ast::Trait(it) => sema.to_def(&it)?.into(), 185 ast::Trait(it) => sema.to_def(&it)?.into(),
163 ast::Impl(it) => return sema.to_def(&it).map(Definition::SelfType), 186 ast::Impl(it) => return sema.to_def(&it).map(Definition::SelfType),
164 ast::MacroRules(it) => return sema.to_def(&it).map(Definition::Macro), 187 ast::Macro(it) => return sema.to_def(&it).map(Definition::Macro),
165 ast::TupleField(it) => return sema.to_def(&it).map(Definition::Field), 188 ast::TupleField(it) => return sema.to_def(&it).map(Definition::Field),
166 ast::RecordField(it) => return sema.to_def(&it).map(Definition::Field), 189 ast::RecordField(it) => return sema.to_def(&it).map(Definition::Field),
167 _ => return None, 190 _ => return None,
@@ -178,15 +201,15 @@ pub(crate) fn resolve_doc_path_for_def(
178) -> Option<hir::ModuleDef> { 201) -> Option<hir::ModuleDef> {
179 match def { 202 match def {
180 Definition::ModuleDef(def) => match def { 203 Definition::ModuleDef(def) => match def {
181 ModuleDef::Module(it) => it.resolve_doc_path(db, &link, ns), 204 hir::ModuleDef::Module(it) => it.resolve_doc_path(db, &link, ns),
182 ModuleDef::Function(it) => it.resolve_doc_path(db, &link, ns), 205 hir::ModuleDef::Function(it) => it.resolve_doc_path(db, &link, ns),
183 ModuleDef::Adt(it) => it.resolve_doc_path(db, &link, ns), 206 hir::ModuleDef::Adt(it) => it.resolve_doc_path(db, &link, ns),
184 ModuleDef::Variant(it) => it.resolve_doc_path(db, &link, ns), 207 hir::ModuleDef::Variant(it) => it.resolve_doc_path(db, &link, ns),
185 ModuleDef::Const(it) => it.resolve_doc_path(db, &link, ns), 208 hir::ModuleDef::Const(it) => it.resolve_doc_path(db, &link, ns),
186 ModuleDef::Static(it) => it.resolve_doc_path(db, &link, ns), 209 hir::ModuleDef::Static(it) => it.resolve_doc_path(db, &link, ns),
187 ModuleDef::Trait(it) => it.resolve_doc_path(db, &link, ns), 210 hir::ModuleDef::Trait(it) => it.resolve_doc_path(db, &link, ns),
188 ModuleDef::TypeAlias(it) => it.resolve_doc_path(db, &link, ns), 211 hir::ModuleDef::TypeAlias(it) => it.resolve_doc_path(db, &link, ns),
189 ModuleDef::BuiltinType(_) => None, 212 hir::ModuleDef::BuiltinType(_) => None,
190 }, 213 },
191 Definition::Macro(it) => it.resolve_doc_path(db, &link, ns), 214 Definition::Macro(it) => it.resolve_doc_path(db, &link, ns),
192 Definition::Field(it) => it.resolve_doc_path(db, &link, ns), 215 Definition::Field(it) => it.resolve_doc_path(db, &link, ns),
@@ -214,7 +237,7 @@ fn get_doc_link(db: &RootDatabase, definition: Definition) -> Option<String> {
214 .and_then(|assoc| match assoc.container(db) { 237 .and_then(|assoc| match assoc.container(db) {
215 AssocItemContainer::Trait(t) => Some(t.into()), 238 AssocItemContainer::Trait(t) => Some(t.into()),
216 AssocItemContainer::Impl(impld) => { 239 AssocItemContainer::Impl(impld) => {
217 impld.target_ty(db).as_adt().map(|adt| adt.into()) 240 impld.self_ty(db).as_adt().map(|adt| adt.into())
218 } 241 }
219 }) 242 })
220 .unwrap_or_else(|| f.clone().into()), 243 .unwrap_or_else(|| f.clone().into()),
@@ -328,28 +351,6 @@ fn rewrite_url_link(db: &RootDatabase, def: ModuleDef, target: &str) -> Option<S
328 .map(|url| url.into_string()) 351 .map(|url| url.into_string())
329} 352}
330 353
331/// Retrieve a link to documentation for the given symbol.
332pub(crate) fn external_docs(
333 db: &RootDatabase,
334 position: &FilePosition,
335) -> Option<DocumentationLink> {
336 let sema = Semantics::new(db);
337 let file = sema.parse(position.file_id).syntax().clone();
338 let token = pick_best(file.token_at_offset(position.offset))?;
339 let token = sema.descend_into_macros(token);
340
341 let node = token.parent()?;
342 let definition = match_ast! {
343 match node {
344 ast::NameRef(name_ref) => NameRefClass::classify(&sema, &name_ref).map(|d| d.referenced(sema.db)),
345 ast::Name(name) => NameClass::classify(&sema, &name).map(|d| d.referenced_or_defined(sema.db)),
346 _ => None,
347 }
348 };
349
350 get_doc_link(db, definition?)
351}
352
353/// Rewrites a markdown document, applying 'callback' to each link. 354/// Rewrites a markdown document, applying 'callback' to each link.
354fn map_links<'e>( 355fn map_links<'e>(
355 events: impl Iterator<Item = Event<'e>>, 356 events: impl Iterator<Item = Event<'e>>,
diff --git a/crates/ide/src/expand_macro.rs b/crates/ide/src/expand_macro.rs
index ffb3a6f7d..9eeabbeda 100644
--- a/crates/ide/src/expand_macro.rs
+++ b/crates/ide/src/expand_macro.rs
@@ -23,6 +23,8 @@ pub struct ExpandedMacro {
23// 23//
24// | VS Code | **Rust Analyzer: Expand macro recursively** 24// | VS Code | **Rust Analyzer: Expand macro recursively**
25// |=== 25// |===
26//
27// image::https://user-images.githubusercontent.com/48062697/113020648-b3973180-917a-11eb-84a9-ecb921293dc5.gif[]
26pub(crate) fn expand_macro(db: &RootDatabase, position: FilePosition) -> Option<ExpandedMacro> { 28pub(crate) fn expand_macro(db: &RootDatabase, position: FilePosition) -> Option<ExpandedMacro> {
27 let sema = Semantics::new(db); 29 let sema = Semantics::new(db);
28 let file = sema.parse(position.file_id); 30 let file = sema.parse(position.file_id);
diff --git a/crates/ide/src/extend_selection.rs b/crates/ide/src/extend_selection.rs
index 5201ce587..7032889ac 100644
--- a/crates/ide/src/extend_selection.rs
+++ b/crates/ide/src/extend_selection.rs
@@ -24,6 +24,8 @@ use crate::FileRange;
24// 24//
25// | VS Code | kbd:[Alt+Shift+→], kbd:[Alt+Shift+←] 25// | VS Code | kbd:[Alt+Shift+→], kbd:[Alt+Shift+←]
26// |=== 26// |===
27//
28// image::https://user-images.githubusercontent.com/48062697/113020651-b42fc800-917a-11eb-8a4f-cf1a07859fac.gif[]
27pub(crate) fn extend_selection(db: &RootDatabase, frange: FileRange) -> TextRange { 29pub(crate) fn extend_selection(db: &RootDatabase, frange: FileRange) -> TextRange {
28 let sema = Semantics::new(db); 30 let sema = Semantics::new(db);
29 let src = sema.parse(frange.file_id); 31 let src = sema.parse(frange.file_id);
diff --git a/crates/ide/src/file_structure.rs b/crates/ide/src/file_structure.rs
index 9f879a66e..19071d6be 100644
--- a/crates/ide/src/file_structure.rs
+++ b/crates/ide/src/file_structure.rs
@@ -35,6 +35,9 @@ pub enum StructureNodeKind {
35// 35//
36// | VS Code | kbd:[Ctrl+Shift+O] 36// | VS Code | kbd:[Ctrl+Shift+O]
37// |=== 37// |===
38//
39// image::https://user-images.githubusercontent.com/48062697/113020654-b42fc800-917a-11eb-8388-e7dc4d92b02e.gif[]
40
38pub(crate) fn file_structure(file: &SourceFile) -> Vec<StructureNode> { 41pub(crate) fn file_structure(file: &SourceFile) -> Vec<StructureNode> {
39 let mut res = Vec::new(); 42 let mut res = Vec::new();
40 let mut stack = Vec::new(); 43 let mut stack = Vec::new();
@@ -172,7 +175,7 @@ fn structure_node(node: &SyntaxNode) -> Option<StructureNode> {
172 }; 175 };
173 Some(node) 176 Some(node)
174 }, 177 },
175 ast::MacroRules(it) => decl(it, StructureNodeKind::SymbolKind(SymbolKind::Macro)), 178 ast::Macro(it) => decl(it, StructureNodeKind::SymbolKind(SymbolKind::Macro)),
176 _ => None, 179 _ => None,
177 } 180 }
178 } 181 }
diff --git a/crates/ide/src/folding_ranges.rs b/crates/ide/src/folding_ranges.rs
index 4b1b24562..153726ce8 100644
--- a/crates/ide/src/folding_ranges.rs
+++ b/crates/ide/src/folding_ranges.rs
@@ -17,6 +17,8 @@ pub enum FoldKind {
17 Block, 17 Block,
18 ArgList, 18 ArgList,
19 Region, 19 Region,
20 Consts,
21 Statics,
20} 22}
21 23
22#[derive(Debug)] 24#[derive(Debug)]
@@ -30,6 +32,8 @@ pub(crate) fn folding_ranges(file: &SourceFile) -> Vec<Fold> {
30 let mut visited_comments = FxHashSet::default(); 32 let mut visited_comments = FxHashSet::default();
31 let mut visited_imports = FxHashSet::default(); 33 let mut visited_imports = FxHashSet::default();
32 let mut visited_mods = FxHashSet::default(); 34 let mut visited_mods = FxHashSet::default();
35 let mut visited_consts = FxHashSet::default();
36 let mut visited_statics = FxHashSet::default();
33 // regions can be nested, here is a LIFO buffer 37 // regions can be nested, here is a LIFO buffer
34 let mut regions_starts: Vec<TextSize> = vec![]; 38 let mut regions_starts: Vec<TextSize> = vec![];
35 39
@@ -91,6 +95,19 @@ pub(crate) fn folding_ranges(file: &SourceFile) -> Vec<Fold> {
91 res.push(Fold { range, kind: FoldKind::Mods }) 95 res.push(Fold { range, kind: FoldKind::Mods })
92 } 96 }
93 } 97 }
98
99 // Fold groups of consts
100 if node.kind() == CONST && !visited_consts.contains(&node) {
101 if let Some(range) = contiguous_range_for_group(&node, &mut visited_consts) {
102 res.push(Fold { range, kind: FoldKind::Consts })
103 }
104 }
105 // Fold groups of consts
106 if node.kind() == STATIC && !visited_statics.contains(&node) {
107 if let Some(range) = contiguous_range_for_group(&node, &mut visited_statics) {
108 res.push(Fold { range, kind: FoldKind::Statics })
109 }
110 }
94 } 111 }
95 } 112 }
96 } 113 }
@@ -250,6 +267,8 @@ mod tests {
250 FoldKind::Block => "block", 267 FoldKind::Block => "block",
251 FoldKind::ArgList => "arglist", 268 FoldKind::ArgList => "arglist",
252 FoldKind::Region => "region", 269 FoldKind::Region => "region",
270 FoldKind::Consts => "consts",
271 FoldKind::Statics => "statics",
253 }; 272 };
254 assert_eq!(kind, &attr.unwrap()); 273 assert_eq!(kind, &attr.unwrap());
255 } 274 }
@@ -457,4 +476,24 @@ calling_function(x,y);
457"#, 476"#,
458 ) 477 )
459 } 478 }
479
480 #[test]
481 fn fold_consecutive_const() {
482 check(
483 r#"
484<fold consts>const FIRST_CONST: &str = "first";
485const SECOND_CONST: &str = "second";</fold>
486 "#,
487 )
488 }
489
490 #[test]
491 fn fold_consecutive_static() {
492 check(
493 r#"
494<fold statics>static FIRST_STATIC: &str = "first";
495static SECOND_STATIC: &str = "second";</fold>
496 "#,
497 )
498 }
460} 499}
diff --git a/crates/ide/src/goto_definition.rs b/crates/ide/src/goto_definition.rs
index a2c97061f..8574d1e3f 100644
--- a/crates/ide/src/goto_definition.rs
+++ b/crates/ide/src/goto_definition.rs
@@ -21,6 +21,8 @@ use crate::{
21// 21//
22// | VS Code | kbd:[F12] 22// | VS Code | kbd:[F12]
23// |=== 23// |===
24//
25// image::https://user-images.githubusercontent.com/48062697/113065563-025fbe00-91b1-11eb-83e4-a5a703610b23.gif[]
24pub(crate) fn goto_definition( 26pub(crate) fn goto_definition(
25 db: &RootDatabase, 27 db: &RootDatabase,
26 position: FilePosition, 28 position: FilePosition,
@@ -918,6 +920,21 @@ fn f() -> impl Iterator<Item$0 = u8> {}
918 } 920 }
919 921
920 #[test] 922 #[test]
923 #[should_panic = "unresolved reference"]
924 fn unknown_assoc_ty() {
925 check(
926 r#"
927trait Iterator {
928 type Item;
929 //^^^^
930}
931
932fn f() -> impl Iterator<Invalid$0 = u8> {}
933 "#,
934 )
935 }
936
937 #[test]
921 fn goto_def_for_assoc_ty_in_path_multiple() { 938 fn goto_def_for_assoc_ty_in_path_multiple() {
922 check( 939 check(
923 r#" 940 r#"
diff --git a/crates/ide/src/goto_implementation.rs b/crates/ide/src/goto_implementation.rs
index f4d7c14a6..05130a237 100644
--- a/crates/ide/src/goto_implementation.rs
+++ b/crates/ide/src/goto_implementation.rs
@@ -16,6 +16,8 @@ use crate::{display::TryToNav, FilePosition, NavigationTarget, RangeInfo};
16// 16//
17// | VS Code | kbd:[Ctrl+F12] 17// | VS Code | kbd:[Ctrl+F12]
18// |=== 18// |===
19//
20// image::https://user-images.githubusercontent.com/48062697/113065566-02f85480-91b1-11eb-9288-aaad8abd8841.gif[]
19pub(crate) fn goto_implementation( 21pub(crate) fn goto_implementation(
20 db: &RootDatabase, 22 db: &RootDatabase,
21 position: FilePosition, 23 position: FilePosition,
diff --git a/crates/ide/src/goto_type_definition.rs b/crates/ide/src/goto_type_definition.rs
index 2d38cb112..9d34b109b 100644
--- a/crates/ide/src/goto_type_definition.rs
+++ b/crates/ide/src/goto_type_definition.rs
@@ -12,6 +12,8 @@ use crate::{display::TryToNav, FilePosition, NavigationTarget, RangeInfo};
12// 12//
13// | VS Code | **Go to Type Definition* 13// | VS Code | **Go to Type Definition*
14// |=== 14// |===
15//
16// image::https://user-images.githubusercontent.com/48062697/113020657-b560f500-917a-11eb-9007-0f809733a338.gif[]
15pub(crate) fn goto_type_definition( 17pub(crate) fn goto_type_definition(
16 db: &RootDatabase, 18 db: &RootDatabase,
17 position: FilePosition, 19 position: FilePosition,
diff --git a/crates/ide/src/hover.rs b/crates/ide/src/hover.rs
index c43089476..5f9edb476 100644
--- a/crates/ide/src/hover.rs
+++ b/crates/ide/src/hover.rs
@@ -82,6 +82,8 @@ pub struct HoverResult {
82// 82//
83// Shows additional information, like type of an expression or documentation for definition when "focusing" code. 83// Shows additional information, like type of an expression or documentation for definition when "focusing" code.
84// Focusing is usually hovering with a mouse, but can also be triggered with a shortcut. 84// Focusing is usually hovering with a mouse, but can also be triggered with a shortcut.
85//
86// image::https://user-images.githubusercontent.com/48062697/113020658-b5f98b80-917a-11eb-9f88-3dbc27320c95.gif[]
85pub(crate) fn hover( 87pub(crate) fn hover(
86 db: &RootDatabase, 88 db: &RootDatabase,
87 position: FilePosition, 89 position: FilePosition,
@@ -195,7 +197,7 @@ fn show_implementations_action(db: &RootDatabase, def: Definition) -> Option<Hov
195 let adt = match def { 197 let adt = match def {
196 Definition::ModuleDef(ModuleDef::Trait(it)) => return it.try_to_nav(db).map(to_action), 198 Definition::ModuleDef(ModuleDef::Trait(it)) => return it.try_to_nav(db).map(to_action),
197 Definition::ModuleDef(ModuleDef::Adt(it)) => Some(it), 199 Definition::ModuleDef(ModuleDef::Adt(it)) => Some(it),
198 Definition::SelfType(it) => it.target_ty(db).as_adt(), 200 Definition::SelfType(it) => it.self_ty(db).as_adt(),
199 _ => None, 201 _ => None,
200 }?; 202 }?;
201 adt.try_to_nav(db).map(to_action) 203 adt.try_to_nav(db).map(to_action)
@@ -318,7 +320,7 @@ fn definition_owner_name(db: &RootDatabase, def: &Definition) -> Option<String>
318 Definition::ModuleDef(md) => match md { 320 Definition::ModuleDef(md) => match md {
319 ModuleDef::Function(f) => match f.as_assoc_item(db)?.container(db) { 321 ModuleDef::Function(f) => match f.as_assoc_item(db)?.container(db) {
320 AssocItemContainer::Trait(t) => Some(t.name(db)), 322 AssocItemContainer::Trait(t) => Some(t.name(db)),
321 AssocItemContainer::Impl(i) => i.target_ty(db).as_adt().map(|adt| adt.name(db)), 323 AssocItemContainer::Impl(i) => i.self_ty(db).as_adt().map(|adt| adt.name(db)),
322 }, 324 },
323 ModuleDef::Variant(e) => Some(e.parent_enum(db).name(db)), 325 ModuleDef::Variant(e) => Some(e.parent_enum(db).name(db)),
324 _ => None, 326 _ => None,
@@ -376,7 +378,7 @@ fn hover_for_definition(
376 }, 378 },
377 Definition::Local(it) => hover_for_local(it, db), 379 Definition::Local(it) => hover_for_local(it, db),
378 Definition::SelfType(impl_def) => { 380 Definition::SelfType(impl_def) => {
379 impl_def.target_ty(db).as_adt().and_then(|adt| from_hir_fmt(db, adt, mod_path)) 381 impl_def.self_ty(db).as_adt().and_then(|adt| from_hir_fmt(db, adt, mod_path))
380 } 382 }
381 Definition::GenericParam(it) => from_hir_fmt(db, it, None), 383 Definition::GenericParam(it) => from_hir_fmt(db, it, None),
382 Definition::Label(it) => Some(Markup::fenced_block(&it.name(db))), 384 Definition::Label(it) => Some(Markup::fenced_block(&it.name(db))),
@@ -470,6 +472,7 @@ fn find_std_module(famous_defs: &FamousDefs, name: &str) -> Option<hir::Module>
470 472
471fn pick_best(tokens: TokenAtOffset<SyntaxToken>) -> Option<SyntaxToken> { 473fn pick_best(tokens: TokenAtOffset<SyntaxToken>) -> Option<SyntaxToken> {
472 return tokens.max_by_key(priority); 474 return tokens.max_by_key(priority);
475
473 fn priority(n: &SyntaxToken) -> usize { 476 fn priority(n: &SyntaxToken) -> usize {
474 match n.kind() { 477 match n.kind() {
475 IDENT | INT_NUMBER | LIFETIME_IDENT | T![self] | T![super] | T![crate] => 3, 478 IDENT | INT_NUMBER | LIFETIME_IDENT | T![self] | T![super] | T![crate] => 3,
@@ -1235,6 +1238,37 @@ fn f() { fo$0o!(); }
1235 } 1238 }
1236 1239
1237 #[test] 1240 #[test]
1241 fn test_hover_macro2_invocation() {
1242 check(
1243 r#"
1244/// foo bar
1245///
1246/// foo bar baz
1247macro foo() {}
1248
1249fn f() { fo$0o!(); }
1250"#,
1251 expect![[r#"
1252 *foo*
1253
1254 ```rust
1255 test
1256 ```
1257
1258 ```rust
1259 macro foo
1260 ```
1261
1262 ---
1263
1264 foo bar
1265
1266 foo bar baz
1267 "#]],
1268 )
1269 }
1270
1271 #[test]
1238 fn test_hover_tuple_field() { 1272 fn test_hover_tuple_field() {
1239 check( 1273 check(
1240 r#"struct TS(String, i32$0);"#, 1274 r#"struct TS(String, i32$0);"#,
diff --git a/crates/ide/src/inlay_hints.rs b/crates/ide/src/inlay_hints.rs
index 16c04eeee..f73edf8b6 100644
--- a/crates/ide/src/inlay_hints.rs
+++ b/crates/ide/src/inlay_hints.rs
@@ -52,6 +52,8 @@ pub struct InlayHint {
52// 52//
53// | VS Code | **Rust Analyzer: Toggle inlay hints* 53// | VS Code | **Rust Analyzer: Toggle inlay hints*
54// |=== 54// |===
55//
56// image::https://user-images.githubusercontent.com/48062697/113020660-b5f98b80-917a-11eb-8d70-3be3fd558cdd.png[]
55pub(crate) fn inlay_hints( 57pub(crate) fn inlay_hints(
56 db: &RootDatabase, 58 db: &RootDatabase,
57 file_id: FileId, 59 file_id: FileId,
@@ -416,7 +418,7 @@ fn get_string_representation(expr: &ast::Expr) -> Option<String> {
416 match expr { 418 match expr {
417 ast::Expr::MethodCallExpr(method_call_expr) => { 419 ast::Expr::MethodCallExpr(method_call_expr) => {
418 let name_ref = method_call_expr.name_ref()?; 420 let name_ref = method_call_expr.name_ref()?;
419 match name_ref.text() { 421 match name_ref.text().as_str() {
420 "clone" => method_call_expr.receiver().map(|rec| rec.to_string()), 422 "clone" => method_call_expr.receiver().map(|rec| rec.to_string()),
421 name_ref => Some(name_ref.to_owned()), 423 name_ref => Some(name_ref.to_owned()),
422 } 424 }
diff --git a/crates/ide/src/join_lines.rs b/crates/ide/src/join_lines.rs
index 4b25135cd..d584190f7 100644
--- a/crates/ide/src/join_lines.rs
+++ b/crates/ide/src/join_lines.rs
@@ -19,6 +19,8 @@ use text_edit::{TextEdit, TextEditBuilder};
19// 19//
20// | VS Code | **Rust Analyzer: Join lines** 20// | VS Code | **Rust Analyzer: Join lines**
21// |=== 21// |===
22//
23// image::https://user-images.githubusercontent.com/48062697/113020661-b6922200-917a-11eb-87c4-b75acc028f11.gif[]
22pub(crate) fn join_lines(file: &SourceFile, range: TextRange) -> TextEdit { 24pub(crate) fn join_lines(file: &SourceFile, range: TextRange) -> TextEdit {
23 let range = if range.is_empty() { 25 let range = if range.is_empty() {
24 let syntax = file.syntax(); 26 let syntax = file.syntax();
diff --git a/crates/ide/src/matching_brace.rs b/crates/ide/src/matching_brace.rs
index 4241a6dac..261dcc255 100644
--- a/crates/ide/src/matching_brace.rs
+++ b/crates/ide/src/matching_brace.rs
@@ -14,6 +14,8 @@ use syntax::{
14// 14//
15// | VS Code | **Rust Analyzer: Find matching brace** 15// | VS Code | **Rust Analyzer: Find matching brace**
16// |=== 16// |===
17//
18// image::https://user-images.githubusercontent.com/48062697/113065573-04298180-91b1-11eb-8dec-d4e2a202f304.gif[]
17pub(crate) fn matching_brace(file: &SourceFile, offset: TextSize) -> Option<TextSize> { 19pub(crate) fn matching_brace(file: &SourceFile, offset: TextSize) -> Option<TextSize> {
18 const BRACES: &[SyntaxKind] = 20 const BRACES: &[SyntaxKind] =
19 &[T!['{'], T!['}'], T!['['], T![']'], T!['('], T![')'], T![<], T![>], T![|], T![|]]; 21 &[T!['{'], T!['}'], T!['['], T![']'], T!['('], T![')'], T![<], T![>], T![|], T![|]];
diff --git a/crates/ide/src/move_item.rs b/crates/ide/src/move_item.rs
index 48690b073..8d37f4f92 100644
--- a/crates/ide/src/move_item.rs
+++ b/crates/ide/src/move_item.rs
@@ -4,10 +4,12 @@ use hir::Semantics;
4use ide_db::{base_db::FileRange, RootDatabase}; 4use ide_db::{base_db::FileRange, RootDatabase};
5use itertools::Itertools; 5use itertools::Itertools;
6use syntax::{ 6use syntax::{
7 algo, ast, match_ast, AstNode, NodeOrToken, SyntaxElement, SyntaxKind, SyntaxNode, TextRange, 7 algo, ast, match_ast, AstNode, SyntaxElement, SyntaxKind, SyntaxNode, SyntaxToken, TextRange,
8 TokenAtOffset,
8}; 9};
9use text_edit::{TextEdit, TextEditBuilder}; 10use text_edit::{TextEdit, TextEditBuilder};
10 11
12#[derive(Copy, Clone, Debug)]
11pub enum Direction { 13pub enum Direction {
12 Up, 14 Up,
13 Down, 15 Down,
@@ -23,6 +25,8 @@ pub enum Direction {
23// | VS Code | **Rust Analyzer: Move item up** 25// | VS Code | **Rust Analyzer: Move item up**
24// | VS Code | **Rust Analyzer: Move item down** 26// | VS Code | **Rust Analyzer: Move item down**
25// |=== 27// |===
28//
29// image::https://user-images.githubusercontent.com/48062697/113065576-04298180-91b1-11eb-91ce-4505e99ed598.gif[]
26pub(crate) fn move_item( 30pub(crate) fn move_item(
27 db: &RootDatabase, 31 db: &RootDatabase,
28 range: FileRange, 32 range: FileRange,
@@ -31,14 +35,19 @@ pub(crate) fn move_item(
31 let sema = Semantics::new(db); 35 let sema = Semantics::new(db);
32 let file = sema.parse(range.file_id); 36 let file = sema.parse(range.file_id);
33 37
34 let item = file.syntax().covering_element(range.range); 38 let item = if range.range.is_empty() {
39 SyntaxElement::Token(pick_best(file.syntax().token_at_offset(range.range.start()))?)
40 } else {
41 file.syntax().covering_element(range.range)
42 };
43
35 find_ancestors(item, direction, range.range) 44 find_ancestors(item, direction, range.range)
36} 45}
37 46
38fn find_ancestors(item: SyntaxElement, direction: Direction, range: TextRange) -> Option<TextEdit> { 47fn find_ancestors(item: SyntaxElement, direction: Direction, range: TextRange) -> Option<TextEdit> {
39 let root = match item { 48 let root = match item {
40 NodeOrToken::Node(node) => node, 49 SyntaxElement::Node(node) => node,
41 NodeOrToken::Token(token) => token.parent()?, 50 SyntaxElement::Token(token) => token.parent()?,
42 }; 51 };
43 52
44 let movable = [ 53 let movable = [
@@ -51,6 +60,11 @@ fn find_ancestors(item: SyntaxElement, direction: Direction, range: TextRange) -
51 SyntaxKind::PARAM, 60 SyntaxKind::PARAM,
52 SyntaxKind::LET_STMT, 61 SyntaxKind::LET_STMT,
53 SyntaxKind::EXPR_STMT, 62 SyntaxKind::EXPR_STMT,
63 SyntaxKind::IF_EXPR,
64 SyntaxKind::FOR_EXPR,
65 SyntaxKind::LOOP_EXPR,
66 SyntaxKind::WHILE_EXPR,
67 SyntaxKind::RETURN_EXPR,
54 SyntaxKind::MATCH_EXPR, 68 SyntaxKind::MATCH_EXPR,
55 SyntaxKind::MACRO_CALL, 69 SyntaxKind::MACRO_CALL,
56 SyntaxKind::TYPE_ALIAS, 70 SyntaxKind::TYPE_ALIAS,
@@ -66,6 +80,7 @@ fn find_ancestors(item: SyntaxElement, direction: Direction, range: TextRange) -
66 SyntaxKind::STATIC, 80 SyntaxKind::STATIC,
67 SyntaxKind::CONST, 81 SyntaxKind::CONST,
68 SyntaxKind::MACRO_RULES, 82 SyntaxKind::MACRO_RULES,
83 SyntaxKind::MACRO_DEF,
69 ]; 84 ];
70 85
71 let ancestor = once(root.clone()) 86 let ancestor = once(root.clone())
@@ -82,11 +97,11 @@ fn move_in_direction(
82) -> Option<TextEdit> { 97) -> Option<TextEdit> {
83 match_ast! { 98 match_ast! {
84 match node { 99 match node {
85 ast::ArgList(it) => swap_sibling_in_list(it.args(), range, direction), 100 ast::ArgList(it) => swap_sibling_in_list(node, it.args(), range, direction),
86 ast::GenericParamList(it) => swap_sibling_in_list(it.generic_params(), range, direction), 101 ast::GenericParamList(it) => swap_sibling_in_list(node, it.generic_params(), range, direction),
87 ast::GenericArgList(it) => swap_sibling_in_list(it.generic_args(), range, direction), 102 ast::GenericArgList(it) => swap_sibling_in_list(node, it.generic_args(), range, direction),
88 ast::VariantList(it) => swap_sibling_in_list(it.variants(), range, direction), 103 ast::VariantList(it) => swap_sibling_in_list(node, it.variants(), range, direction),
89 ast::TypeBoundList(it) => swap_sibling_in_list(it.bounds(), range, direction), 104 ast::TypeBoundList(it) => swap_sibling_in_list(node, it.bounds(), range, direction),
90 _ => Some(replace_nodes(node, &match direction { 105 _ => Some(replace_nodes(node, &match direction {
91 Direction::Up => node.prev_sibling(), 106 Direction::Up => node.prev_sibling(),
92 Direction::Down => node.next_sibling(), 107 Direction::Down => node.next_sibling(),
@@ -96,19 +111,27 @@ fn move_in_direction(
96} 111}
97 112
98fn swap_sibling_in_list<A: AstNode + Clone, I: Iterator<Item = A>>( 113fn swap_sibling_in_list<A: AstNode + Clone, I: Iterator<Item = A>>(
114 node: &SyntaxNode,
99 list: I, 115 list: I,
100 range: TextRange, 116 range: TextRange,
101 direction: Direction, 117 direction: Direction,
102) -> Option<TextEdit> { 118) -> Option<TextEdit> {
103 let (l, r) = list 119 let list_lookup = list
104 .tuple_windows() 120 .tuple_windows()
105 .filter(|(l, r)| match direction { 121 .filter(|(l, r)| match direction {
106 Direction::Up => r.syntax().text_range().contains_range(range), 122 Direction::Up => r.syntax().text_range().contains_range(range),
107 Direction::Down => l.syntax().text_range().contains_range(range), 123 Direction::Down => l.syntax().text_range().contains_range(range),
108 }) 124 })
109 .next()?; 125 .next();
110 126
111 Some(replace_nodes(l.syntax(), r.syntax())) 127 if let Some((l, r)) = list_lookup {
128 Some(replace_nodes(l.syntax(), r.syntax()))
129 } else {
130 // Cursor is beyond any movable list item (for example, on curly brace in enum).
131 // It's not necessary, that parent of list is movable (arg list's parent is not, for example),
132 // and we have to continue tree traversal to find suitable node.
133 find_ancestors(SyntaxElement::Node(node.parent()?), direction, range)
134 }
112} 135}
113 136
114fn replace_nodes(first: &SyntaxNode, second: &SyntaxNode) -> TextEdit { 137fn replace_nodes(first: &SyntaxNode, second: &SyntaxNode) -> TextEdit {
@@ -120,6 +143,18 @@ fn replace_nodes(first: &SyntaxNode, second: &SyntaxNode) -> TextEdit {
120 edit.finish() 143 edit.finish()
121} 144}
122 145
146fn pick_best(tokens: TokenAtOffset<SyntaxToken>) -> Option<SyntaxToken> {
147 return tokens.max_by_key(priority);
148
149 fn priority(n: &SyntaxToken) -> usize {
150 match n.kind() {
151 SyntaxKind::IDENT | SyntaxKind::LIFETIME_IDENT => 2,
152 kind if kind.is_trivia() => 0,
153 _ => 1,
154 }
155 }
156}
157
123#[cfg(test)] 158#[cfg(test)]
124mod tests { 159mod tests {
125 use crate::fixture; 160 use crate::fixture;
@@ -264,6 +299,107 @@ fn main() {
264 "#]], 299 "#]],
265 Direction::Up, 300 Direction::Up,
266 ); 301 );
302 check(
303 r#"
304fn main() {
305 println!("Hello, world");
306
307 if true {
308 println!("Test");
309 }$0$0
310}
311 "#,
312 expect![[r#"
313fn main() {
314 if true {
315 println!("Test");
316 }
317
318 println!("Hello, world");
319}
320 "#]],
321 Direction::Up,
322 );
323 check(
324 r#"
325fn main() {
326 println!("Hello, world");
327
328 for i in 0..10 {
329 println!("Test");
330 }$0$0
331}
332 "#,
333 expect![[r#"
334fn main() {
335 for i in 0..10 {
336 println!("Test");
337 }
338
339 println!("Hello, world");
340}
341 "#]],
342 Direction::Up,
343 );
344 check(
345 r#"
346fn main() {
347 println!("Hello, world");
348
349 loop {
350 println!("Test");
351 }$0$0
352}
353 "#,
354 expect![[r#"
355fn main() {
356 loop {
357 println!("Test");
358 }
359
360 println!("Hello, world");
361}
362 "#]],
363 Direction::Up,
364 );
365 check(
366 r#"
367fn main() {
368 println!("Hello, world");
369
370 while true {
371 println!("Test");
372 }$0$0
373}
374 "#,
375 expect![[r#"
376fn main() {
377 while true {
378 println!("Test");
379 }
380
381 println!("Hello, world");
382}
383 "#]],
384 Direction::Up,
385 );
386 check(
387 r#"
388fn main() {
389 println!("Hello, world");
390
391 return 123;$0$0
392}
393 "#,
394 expect![[r#"
395fn main() {
396 return 123;
397
398 println!("Hello, world");
399}
400 "#]],
401 Direction::Up,
402 );
267 } 403 }
268 404
269 #[test] 405 #[test]
@@ -614,6 +750,115 @@ fn test() {
614 } 750 }
615 751
616 #[test] 752 #[test]
753 fn test_cursor_at_item_start() {
754 check(
755 r#"
756$0$0#[derive(Debug)]
757enum FooBar {
758 Foo,
759 Bar,
760}
761
762fn main() {}
763 "#,
764 expect![[r#"
765fn main() {}
766
767#[derive(Debug)]
768enum FooBar {
769 Foo,
770 Bar,
771}
772 "#]],
773 Direction::Down,
774 );
775 check(
776 r#"
777$0$0enum FooBar {
778 Foo,
779 Bar,
780}
781
782fn main() {}
783 "#,
784 expect![[r#"
785fn main() {}
786
787enum FooBar {
788 Foo,
789 Bar,
790}
791 "#]],
792 Direction::Down,
793 );
794 check(
795 r#"
796struct Test;
797
798trait SomeTrait {}
799
800$0$0impl SomeTrait for Test {}
801
802fn main() {}
803 "#,
804 expect![[r#"
805struct Test;
806
807impl SomeTrait for Test {}
808
809trait SomeTrait {}
810
811fn main() {}
812 "#]],
813 Direction::Up,
814 );
815 }
816
817 #[test]
818 fn test_cursor_at_item_end() {
819 check(
820 r#"
821enum FooBar {
822 Foo,
823 Bar,
824}$0$0
825
826fn main() {}
827 "#,
828 expect![[r#"
829fn main() {}
830
831enum FooBar {
832 Foo,
833 Bar,
834}
835 "#]],
836 Direction::Down,
837 );
838 check(
839 r#"
840struct Test;
841
842trait SomeTrait {}
843
844impl SomeTrait for Test {}$0$0
845
846fn main() {}
847 "#,
848 expect![[r#"
849struct Test;
850
851impl SomeTrait for Test {}
852
853trait SomeTrait {}
854
855fn main() {}
856 "#]],
857 Direction::Up,
858 );
859 }
860
861 #[test]
617 fn handles_empty_file() { 862 fn handles_empty_file() {
618 check(r#"$0$0"#, expect![[r#""#]], Direction::Up); 863 check(r#"$0$0"#, expect![[r#""#]], Direction::Up);
619 } 864 }
diff --git a/crates/ide/src/parent_module.rs b/crates/ide/src/parent_module.rs
index 22b0d6ecb..99365c8a7 100644
--- a/crates/ide/src/parent_module.rs
+++ b/crates/ide/src/parent_module.rs
@@ -18,6 +18,8 @@ use crate::NavigationTarget;
18// 18//
19// | VS Code | **Rust Analyzer: Locate parent module** 19// | VS Code | **Rust Analyzer: Locate parent module**
20// |=== 20// |===
21//
22// image::https://user-images.githubusercontent.com/48062697/113065580-04c21800-91b1-11eb-9a32-00086161c0bd.gif[]
21 23
22/// This returns `Vec` because a module may be included from several places. 24/// This returns `Vec` because a module may be included from several places.
23pub(crate) fn parent_module(db: &RootDatabase, position: FilePosition) -> Vec<NavigationTarget> { 25pub(crate) fn parent_module(db: &RootDatabase, position: FilePosition) -> Vec<NavigationTarget> {
diff --git a/crates/ide/src/references.rs b/crates/ide/src/references.rs
index 95ed8a045..11ca7ec6b 100644
--- a/crates/ide/src/references.rs
+++ b/crates/ide/src/references.rs
@@ -48,6 +48,8 @@ pub struct Declaration {
48// 48//
49// | VS Code | kbd:[Shift+Alt+F12] 49// | VS Code | kbd:[Shift+Alt+F12]
50// |=== 50// |===
51//
52// image::https://user-images.githubusercontent.com/48062697/113020670-b7c34f00-917a-11eb-8003-370ac5f2b3cb.gif[]
51pub(crate) fn find_all_refs( 53pub(crate) fn find_all_refs(
52 sema: &Semantics<RootDatabase>, 54 sema: &Semantics<RootDatabase>,
53 position: FilePosition, 55 position: FilePosition,
diff --git a/crates/ide/src/references/rename.rs b/crates/ide/src/references/rename.rs
index 26d6dc9c9..2408a0181 100644
--- a/crates/ide/src/references/rename.rs
+++ b/crates/ide/src/references/rename.rs
@@ -70,6 +70,8 @@ pub(crate) fn prepare_rename(
70// 70//
71// | VS Code | kbd:[F2] 71// | VS Code | kbd:[F2]
72// |=== 72// |===
73//
74// image::https://user-images.githubusercontent.com/48062697/113065582-055aae80-91b1-11eb-8ade-2b58e6d81883.gif[]
73pub(crate) fn rename( 75pub(crate) fn rename(
74 db: &RootDatabase, 76 db: &RootDatabase,
75 position: FilePosition, 77 position: FilePosition,
@@ -307,7 +309,7 @@ fn rename_to_self(sema: &Semantics<RootDatabase>, local: hir::Local) -> RenameRe
307 hir::AssocItemContainer::Impl(impl_) => impl_, 309 hir::AssocItemContainer::Impl(impl_) => impl_,
308 }; 310 };
309 let first_param_ty = first_param.ty(); 311 let first_param_ty = first_param.ty();
310 let impl_ty = impl_.target_ty(sema.db); 312 let impl_ty = impl_.self_ty(sema.db);
311 let (ty, self_param) = if impl_ty.remove_ref().is_some() { 313 let (ty, self_param) = if impl_ty.remove_ref().is_some() {
312 // if the impl is a ref to the type we can just match the `&T` with self directly 314 // if the impl is a ref to the type we can just match the `&T` with self directly
313 (first_param_ty.clone(), "self") 315 (first_param_ty.clone(), "self")
diff --git a/crates/ide/src/runnables.rs b/crates/ide/src/runnables.rs
index 7e4c5a078..3eb9e27ee 100644
--- a/crates/ide/src/runnables.rs
+++ b/crates/ide/src/runnables.rs
@@ -98,6 +98,7 @@ impl Runnable {
98// 98//
99// | VS Code | **Rust Analyzer: Run** 99// | VS Code | **Rust Analyzer: Run**
100// |=== 100// |===
101// image::https://user-images.githubusercontent.com/48062697/113065583-055aae80-91b1-11eb-958f-d67efcaf6a2f.gif[]
101pub(crate) fn runnables(db: &RootDatabase, file_id: FileId) -> Vec<Runnable> { 102pub(crate) fn runnables(db: &RootDatabase, file_id: FileId) -> Vec<Runnable> {
102 let sema = Semantics::new(db); 103 let sema = Semantics::new(db);
103 104
@@ -298,7 +299,7 @@ fn module_def_doctest(sema: &Semantics<RootDatabase>, def: hir::ModuleDef) -> Op
298 // FIXME: this also looks very wrong 299 // FIXME: this also looks very wrong
299 if let Some(assoc_def) = assoc_def { 300 if let Some(assoc_def) = assoc_def {
300 if let hir::AssocItemContainer::Impl(imp) = assoc_def.container(sema.db) { 301 if let hir::AssocItemContainer::Impl(imp) = assoc_def.container(sema.db) {
301 let ty = imp.target_ty(sema.db); 302 let ty = imp.self_ty(sema.db);
302 if let Some(adt) = ty.as_adt() { 303 if let Some(adt) = ty.as_adt() {
303 let name = adt.name(sema.db); 304 let name = adt.name(sema.db);
304 let idx = path.rfind(':').map_or(0, |idx| idx + 1); 305 let idx = path.rfind(':').map_or(0, |idx| idx + 1);
diff --git a/crates/ide/src/status.rs b/crates/ide/src/status.rs
index 137c38c0d..49fde1945 100644
--- a/crates/ide/src/status.rs
+++ b/crates/ide/src/status.rs
@@ -31,6 +31,7 @@ fn macro_syntax_tree_stats(db: &RootDatabase) -> SyntaxTreeStats {
31// 31//
32// | VS Code | **Rust Analyzer: Status** 32// | VS Code | **Rust Analyzer: Status**
33// |=== 33// |===
34// image::https://user-images.githubusercontent.com/48062697/113065584-05f34500-91b1-11eb-98cc-5c196f76be7f.gif[]
34pub(crate) fn status(db: &RootDatabase, file_id: Option<FileId>) -> String { 35pub(crate) fn status(db: &RootDatabase, file_id: Option<FileId>) -> String {
35 let mut buf = String::new(); 36 let mut buf = String::new();
36 format_to!(buf, "{}\n", FileTextQuery.in_db(db).entries::<FilesStats>()); 37 format_to!(buf, "{}\n", FileTextQuery.in_db(db).entries::<FilesStats>());
diff --git a/crates/ide/src/syntax_highlighting.rs b/crates/ide/src/syntax_highlighting.rs
index e25b698e0..67a10766b 100644
--- a/crates/ide/src/syntax_highlighting.rs
+++ b/crates/ide/src/syntax_highlighting.rs
@@ -5,7 +5,7 @@ mod injector;
5 5
6mod highlight; 6mod highlight;
7mod format; 7mod format;
8mod macro_rules; 8mod macro_;
9mod inject; 9mod inject;
10 10
11mod html; 11mod html;
@@ -24,8 +24,8 @@ use syntax::{
24 24
25use crate::{ 25use crate::{
26 syntax_highlighting::{ 26 syntax_highlighting::{
27 format::highlight_format_string, highlights::Highlights, 27 format::highlight_format_string, highlights::Highlights, macro_::MacroHighlighter,
28 macro_rules::MacroRulesHighlighter, tags::Highlight, 28 tags::Highlight,
29 }, 29 },
30 FileId, HlMod, HlTag, 30 FileId, HlMod, HlTag,
31}; 31};
@@ -93,8 +93,8 @@ fn traverse(
93 let mut bindings_shadow_count: FxHashMap<Name, u32> = FxHashMap::default(); 93 let mut bindings_shadow_count: FxHashMap<Name, u32> = FxHashMap::default();
94 94
95 let mut current_macro_call: Option<ast::MacroCall> = None; 95 let mut current_macro_call: Option<ast::MacroCall> = None;
96 let mut current_macro_rules: Option<ast::MacroRules> = None; 96 let mut current_macro: Option<ast::Macro> = None;
97 let mut macro_rules_highlighter = MacroRulesHighlighter::default(); 97 let mut macro_highlighter = MacroHighlighter::default();
98 let mut inside_attribute = false; 98 let mut inside_attribute = false;
99 99
100 // Walk all nodes, keeping track of whether we are inside a macro or not. 100 // Walk all nodes, keeping track of whether we are inside a macro or not.
@@ -129,16 +129,16 @@ fn traverse(
129 _ => (), 129 _ => (),
130 } 130 }
131 131
132 match event.clone().map(|it| it.into_node().and_then(ast::MacroRules::cast)) { 132 match event.clone().map(|it| it.into_node().and_then(ast::Macro::cast)) {
133 WalkEvent::Enter(Some(mac)) => { 133 WalkEvent::Enter(Some(mac)) => {
134 macro_rules_highlighter.init(); 134 macro_highlighter.init();
135 current_macro_rules = Some(mac); 135 current_macro = Some(mac);
136 continue; 136 continue;
137 } 137 }
138 WalkEvent::Leave(Some(mac)) => { 138 WalkEvent::Leave(Some(mac)) => {
139 assert_eq!(current_macro_rules, Some(mac)); 139 assert_eq!(current_macro, Some(mac));
140 current_macro_rules = None; 140 current_macro = None;
141 macro_rules_highlighter = MacroRulesHighlighter::default(); 141 macro_highlighter = MacroHighlighter::default();
142 } 142 }
143 _ => (), 143 _ => (),
144 } 144 }
@@ -164,9 +164,9 @@ fn traverse(
164 164
165 let range = element.text_range(); 165 let range = element.text_range();
166 166
167 if current_macro_rules.is_some() { 167 if current_macro.is_some() {
168 if let Some(tok) = element.as_token() { 168 if let Some(tok) = element.as_token() {
169 macro_rules_highlighter.advance(tok); 169 macro_highlighter.advance(tok);
170 } 170 }
171 } 171 }
172 172
@@ -200,7 +200,7 @@ fn traverse(
200 } 200 }
201 } 201 }
202 202
203 if let Some(_) = macro_rules_highlighter.highlight(element_to_highlight.clone()) { 203 if let Some(_) = macro_highlighter.highlight(element_to_highlight.clone()) {
204 continue; 204 continue;
205 } 205 }
206 206
diff --git a/crates/ide/src/syntax_highlighting/format.rs b/crates/ide/src/syntax_highlighting/format.rs
index e503abc93..5bbadb0f4 100644
--- a/crates/ide/src/syntax_highlighting/format.rs
+++ b/crates/ide/src/syntax_highlighting/format.rs
@@ -31,7 +31,7 @@ fn is_format_string(string: &ast::String) -> Option<()> {
31 let parent = string.syntax().parent()?; 31 let parent = string.syntax().parent()?;
32 32
33 let name = parent.parent().and_then(ast::MacroCall::cast)?.path()?.segment()?.name_ref()?; 33 let name = parent.parent().and_then(ast::MacroCall::cast)?.path()?.segment()?.name_ref()?;
34 if !matches!(name.text(), "format_args" | "format_args_nl") { 34 if !matches!(name.text().as_str(), "format_args" | "format_args_nl") {
35 return None; 35 return None;
36 } 36 }
37 37
diff --git a/crates/ide/src/syntax_highlighting/highlight.rs b/crates/ide/src/syntax_highlighting/highlight.rs
index b0cfdd8b7..5ccb84714 100644
--- a/crates/ide/src/syntax_highlighting/highlight.rs
+++ b/crates/ide/src/syntax_highlighting/highlight.rs
@@ -1,6 +1,6 @@
1//! Computes color for a single element. 1//! Computes color for a single element.
2 2
3use hir::{AsAssocItem, Semantics, VariantDef}; 3use hir::{AsAssocItem, AssocItemContainer, Semantics, VariantDef};
4use ide_db::{ 4use ide_db::{
5 defs::{Definition, NameClass, NameRefClass}, 5 defs::{Definition, NameClass, NameRefClass},
6 RootDatabase, SymbolKind, 6 RootDatabase, SymbolKind,
@@ -275,12 +275,24 @@ fn highlight_def(db: &RootDatabase, def: Definition) -> Highlight {
275 hir::ModuleDef::Module(_) => HlTag::Symbol(SymbolKind::Module), 275 hir::ModuleDef::Module(_) => HlTag::Symbol(SymbolKind::Module),
276 hir::ModuleDef::Function(func) => { 276 hir::ModuleDef::Function(func) => {
277 let mut h = Highlight::new(HlTag::Symbol(SymbolKind::Function)); 277 let mut h = Highlight::new(HlTag::Symbol(SymbolKind::Function));
278 if func.as_assoc_item(db).is_some() { 278 if let Some(item) = func.as_assoc_item(db) {
279 h |= HlMod::Associated; 279 h |= HlMod::Associated;
280 if func.self_param(db).is_none() { 280 if func.self_param(db).is_none() {
281 h |= HlMod::Static 281 h |= HlMod::Static
282 } 282 }
283
284 match item.container(db) {
285 AssocItemContainer::Impl(i) => {
286 if i.trait_(db).is_some() {
287 h |= HlMod::Trait;
288 }
289 }
290 AssocItemContainer::Trait(_t) => {
291 h |= HlMod::Trait;
292 }
293 }
283 } 294 }
295
284 if func.is_unsafe(db) { 296 if func.is_unsafe(db) {
285 h |= HlMod::Unsafe; 297 h |= HlMod::Unsafe;
286 } 298 }
@@ -292,9 +304,20 @@ fn highlight_def(db: &RootDatabase, def: Definition) -> Highlight {
292 hir::ModuleDef::Variant(_) => HlTag::Symbol(SymbolKind::Variant), 304 hir::ModuleDef::Variant(_) => HlTag::Symbol(SymbolKind::Variant),
293 hir::ModuleDef::Const(konst) => { 305 hir::ModuleDef::Const(konst) => {
294 let mut h = Highlight::new(HlTag::Symbol(SymbolKind::Const)); 306 let mut h = Highlight::new(HlTag::Symbol(SymbolKind::Const));
295 if konst.as_assoc_item(db).is_some() { 307 if let Some(item) = konst.as_assoc_item(db) {
296 h |= HlMod::Associated 308 h |= HlMod::Associated;
309 match item.container(db) {
310 AssocItemContainer::Impl(i) => {
311 if i.trait_(db).is_some() {
312 h |= HlMod::Trait;
313 }
314 }
315 AssocItemContainer::Trait(_t) => {
316 h |= HlMod::Trait;
317 }
318 }
297 } 319 }
320
298 return h; 321 return h;
299 } 322 }
300 hir::ModuleDef::Trait(_) => HlTag::Symbol(SymbolKind::Trait), 323 hir::ModuleDef::Trait(_) => HlTag::Symbol(SymbolKind::Trait),
@@ -362,6 +385,10 @@ fn highlight_method_call(
362 if func.is_unsafe(sema.db) || sema.is_unsafe_method_call(&method_call) { 385 if func.is_unsafe(sema.db) || sema.is_unsafe_method_call(&method_call) {
363 h |= HlMod::Unsafe; 386 h |= HlMod::Unsafe;
364 } 387 }
388 if func.as_assoc_item(sema.db).and_then(|it| it.containing_trait(sema.db)).is_some() {
389 h |= HlMod::Trait
390 }
391
365 if let Some(self_param) = func.self_param(sema.db) { 392 if let Some(self_param) = func.self_param(sema.db) {
366 match self_param.access(sema.db) { 393 match self_param.access(sema.db) {
367 hir::Access::Shared => (), 394 hir::Access::Shared => (),
diff --git a/crates/ide/src/syntax_highlighting/inject.rs b/crates/ide/src/syntax_highlighting/inject.rs
index 38bf49348..b62d43256 100644
--- a/crates/ide/src/syntax_highlighting/inject.rs
+++ b/crates/ide/src/syntax_highlighting/inject.rs
@@ -11,7 +11,8 @@ use syntax::{
11}; 11};
12 12
13use crate::{ 13use crate::{
14 doc_links::extract_definitions_from_markdown, Analysis, HlMod, HlRange, HlTag, RootDatabase, 14 doc_links::{extract_definitions_from_markdown, resolve_doc_path_for_def},
15 Analysis, HlMod, HlRange, HlTag, RootDatabase,
15}; 16};
16 17
17use super::{highlights::Highlights, injector::Injector}; 18use super::{highlights::Highlights, injector::Injector};
@@ -109,8 +110,7 @@ fn doc_attributes<'node>(
109 ast::Impl(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::SelfType(def))), 110 ast::Impl(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::SelfType(def))),
110 ast::RecordField(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::Field(def))), 111 ast::RecordField(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::Field(def))),
111 ast::TupleField(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::Field(def))), 112 ast::TupleField(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::Field(def))),
112 ast::MacroRules(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::Macro(def))), 113 ast::Macro(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::Macro(def))),
113 // ast::MacroDef(it) => sema.to_def(&it).map(|def| (Box::new(it) as _, def.attrs(sema.db))),
114 // ast::Use(it) => sema.to_def(&it).map(|def| (Box::new(it) as _, def.attrs(sema.db))), 114 // ast::Use(it) => sema.to_def(&it).map(|def| (Box::new(it) as _, def.attrs(sema.db))),
115 _ => return None 115 _ => return None
116 } 116 }
@@ -191,7 +191,7 @@ pub(super) fn doc_comment(
191 extract_definitions_from_markdown(line) 191 extract_definitions_from_markdown(line)
192 .into_iter() 192 .into_iter()
193 .filter_map(|(range, link, ns)| { 193 .filter_map(|(range, link, ns)| {
194 Some(range).zip(validate_intra_doc_link(sema.db, &def, &link, ns)) 194 Some(range).zip(resolve_doc_path_for_def(sema.db, def, &link, ns))
195 }) 195 })
196 .map(|(Range { start, end }, def)| { 196 .map(|(Range { start, end }, def)| {
197 ( 197 (
@@ -284,33 +284,6 @@ fn find_doc_string_in_attr(attr: &hir::Attr, it: &ast::Attr) -> Option<ast::Stri
284 } 284 }
285} 285}
286 286
287fn validate_intra_doc_link(
288 db: &RootDatabase,
289 def: &Definition,
290 link: &str,
291 ns: Option<hir::Namespace>,
292) -> Option<hir::ModuleDef> {
293 match def {
294 Definition::ModuleDef(def) => match def {
295 hir::ModuleDef::Module(it) => it.resolve_doc_path(db, &link, ns),
296 hir::ModuleDef::Function(it) => it.resolve_doc_path(db, &link, ns),
297 hir::ModuleDef::Adt(it) => it.resolve_doc_path(db, &link, ns),
298 hir::ModuleDef::Variant(it) => it.resolve_doc_path(db, &link, ns),
299 hir::ModuleDef::Const(it) => it.resolve_doc_path(db, &link, ns),
300 hir::ModuleDef::Static(it) => it.resolve_doc_path(db, &link, ns),
301 hir::ModuleDef::Trait(it) => it.resolve_doc_path(db, &link, ns),
302 hir::ModuleDef::TypeAlias(it) => it.resolve_doc_path(db, &link, ns),
303 hir::ModuleDef::BuiltinType(_) => None,
304 },
305 Definition::Macro(it) => it.resolve_doc_path(db, &link, ns),
306 Definition::Field(it) => it.resolve_doc_path(db, &link, ns),
307 Definition::SelfType(_)
308 | Definition::Local(_)
309 | Definition::GenericParam(_)
310 | Definition::Label(_) => None,
311 }
312}
313
314fn module_def_to_hl_tag(def: hir::ModuleDef) -> HlTag { 287fn module_def_to_hl_tag(def: hir::ModuleDef) -> HlTag {
315 let symbol = match def { 288 let symbol = match def {
316 hir::ModuleDef::Module(_) => SymbolKind::Module, 289 hir::ModuleDef::Module(_) => SymbolKind::Module,
diff --git a/crates/ide/src/syntax_highlighting/macro_rules.rs b/crates/ide/src/syntax_highlighting/macro_.rs
index 44620e912..819704294 100644
--- a/crates/ide/src/syntax_highlighting/macro_rules.rs
+++ b/crates/ide/src/syntax_highlighting/macro_.rs
@@ -4,18 +4,18 @@ use syntax::{SyntaxElement, SyntaxKind, SyntaxToken, TextRange, T};
4use crate::{HlRange, HlTag}; 4use crate::{HlRange, HlTag};
5 5
6#[derive(Default)] 6#[derive(Default)]
7pub(super) struct MacroRulesHighlighter { 7pub(super) struct MacroHighlighter {
8 state: Option<MacroMatcherParseState>, 8 state: Option<MacroMatcherParseState>,
9} 9}
10 10
11impl MacroRulesHighlighter { 11impl MacroHighlighter {
12 pub(super) fn init(&mut self) { 12 pub(super) fn init(&mut self) {
13 self.state = Some(MacroMatcherParseState::default()); 13 self.state = Some(MacroMatcherParseState::default());
14 } 14 }
15 15
16 pub(super) fn advance(&mut self, token: &SyntaxToken) { 16 pub(super) fn advance(&mut self, token: &SyntaxToken) {
17 if let Some(state) = self.state.as_mut() { 17 if let Some(state) = self.state.as_mut() {
18 update_macro_rules_state(state, token); 18 update_macro_state(state, token);
19 } 19 }
20 } 20 }
21 21
@@ -74,9 +74,9 @@ impl RuleState {
74 } 74 }
75} 75}
76 76
77fn update_macro_rules_state(state: &mut MacroMatcherParseState, tok: &SyntaxToken) { 77fn update_macro_state(state: &mut MacroMatcherParseState, tok: &SyntaxToken) {
78 if !state.in_invoc_body { 78 if !state.in_invoc_body {
79 if tok.kind() == T!['{'] { 79 if tok.kind() == T!['{'] || tok.kind() == T!['('] {
80 state.in_invoc_body = true; 80 state.in_invoc_body = true;
81 } 81 }
82 return; 82 return;
diff --git a/crates/ide/src/syntax_highlighting/tags.rs b/crates/ide/src/syntax_highlighting/tags.rs
index 93db79b89..1cec991aa 100644
--- a/crates/ide/src/syntax_highlighting/tags.rs
+++ b/crates/ide/src/syntax_highlighting/tags.rs
@@ -58,6 +58,8 @@ pub enum HlMod {
58 Associated, 58 Associated,
59 /// Used for intra doc links in doc injection. 59 /// Used for intra doc links in doc injection.
60 IntraDocLink, 60 IntraDocLink,
61 /// Used for items in traits and trait impls.
62 Trait,
61 63
62 /// Keep this last! 64 /// Keep this last!
63 Unsafe, 65 Unsafe,
@@ -158,6 +160,7 @@ impl HlMod {
158 HlMod::Callable, 160 HlMod::Callable,
159 HlMod::Static, 161 HlMod::Static,
160 HlMod::Associated, 162 HlMod::Associated,
163 HlMod::Trait,
161 HlMod::Unsafe, 164 HlMod::Unsafe,
162 ]; 165 ];
163 166
@@ -174,6 +177,7 @@ impl HlMod {
174 HlMod::IntraDocLink => "intra_doc_link", 177 HlMod::IntraDocLink => "intra_doc_link",
175 HlMod::Mutable => "mutable", 178 HlMod::Mutable => "mutable",
176 HlMod::Static => "static", 179 HlMod::Static => "static",
180 HlMod::Trait => "trait",
177 HlMod::Unsafe => "unsafe", 181 HlMod::Unsafe => "unsafe",
178 } 182 }
179 } 183 }
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_assoc_functions.html b/crates/ide/src/syntax_highlighting/test_data/highlight_assoc_functions.html
index 4635ea927..8cde3906c 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_assoc_functions.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_assoc_functions.html
@@ -47,12 +47,12 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
47<span class="brace">}</span> 47<span class="brace">}</span>
48 48
49<span class="keyword">trait</span> <span class="trait declaration">t</span> <span class="brace">{</span> 49<span class="keyword">trait</span> <span class="trait declaration">t</span> <span class="brace">{</span>
50 <span class="keyword">fn</span> <span class="function declaration static associated">t_is_static</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span> 50 <span class="keyword">fn</span> <span class="function declaration static associated trait">t_is_static</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span>
51 <span class="keyword">fn</span> <span class="function declaration associated">t_is_not_static</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword declaration">self</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span> 51 <span class="keyword">fn</span> <span class="function declaration associated trait">t_is_not_static</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword declaration">self</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span>
52<span class="brace">}</span> 52<span class="brace">}</span>
53 53
54<span class="keyword">impl</span> <span class="trait">t</span> <span class="keyword">for</span> <span class="struct">foo</span> <span class="brace">{</span> 54<span class="keyword">impl</span> <span class="trait">t</span> <span class="keyword">for</span> <span class="struct">foo</span> <span class="brace">{</span>
55 <span class="keyword">pub</span> <span class="keyword">fn</span> <span class="function declaration static associated">is_static</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span> 55 <span class="keyword">pub</span> <span class="keyword">fn</span> <span class="function declaration static associated trait">is_static</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span>
56 <span class="keyword">pub</span> <span class="keyword">fn</span> <span class="function declaration associated">is_not_static</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword declaration">self</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span> 56 <span class="keyword">pub</span> <span class="keyword">fn</span> <span class="function declaration associated trait">is_not_static</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword declaration">self</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span>
57<span class="brace">}</span> 57<span class="brace">}</span>
58 </code></pre> \ No newline at end of file 58 </code></pre> \ No newline at end of file
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_injection.html b/crates/ide/src/syntax_highlighting/test_data/highlight_injection.html
index 9215ddd9e..7c6694a27 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_injection.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_injection.html
@@ -42,7 +42,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
42<span class="keyword">fn</span> <span class="function declaration">main</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span> 42<span class="keyword">fn</span> <span class="function declaration">main</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span>
43 <span class="function">fixture</span><span class="parenthesis">(</span><span class="string_literal">r#"</span> 43 <span class="function">fixture</span><span class="parenthesis">(</span><span class="string_literal">r#"</span>
44 <span class="keyword">trait</span> <span class="trait declaration">Foo</span> <span class="brace">{</span> 44 <span class="keyword">trait</span> <span class="trait declaration">Foo</span> <span class="brace">{</span>
45 <span class="keyword">fn</span> <span class="function declaration static associated">foo</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span> 45 <span class="keyword">fn</span> <span class="function declaration static associated trait">foo</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span>
46 <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"2 + 2 = {}"</span><span class="comma">,</span> <span class="numeric_literal">4</span><span class="parenthesis">)</span><span class="semicolon">;</span> 46 <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"2 + 2 = {}"</span><span class="comma">,</span> <span class="numeric_literal">4</span><span class="parenthesis">)</span><span class="semicolon">;</span>
47 <span class="brace">}</span> 47 <span class="brace">}</span>
48 <span class="brace">}</span><span class="string_literal">"#</span> 48 <span class="brace">}</span><span class="string_literal">"#</span>
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html b/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html
index 6a6555208..72910421d 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html
@@ -62,11 +62,11 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
62<span class="brace">}</span> 62<span class="brace">}</span>
63 63
64<span class="keyword">trait</span> <span class="trait declaration">DoTheAutoref</span> <span class="brace">{</span> 64<span class="keyword">trait</span> <span class="trait declaration">DoTheAutoref</span> <span class="brace">{</span>
65 <span class="keyword">fn</span> <span class="function declaration associated">calls_autoref</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword declaration">self</span><span class="parenthesis">)</span><span class="semicolon">;</span> 65 <span class="keyword">fn</span> <span class="function declaration associated trait">calls_autoref</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword declaration">self</span><span class="parenthesis">)</span><span class="semicolon">;</span>
66<span class="brace">}</span> 66<span class="brace">}</span>
67 67
68<span class="keyword">impl</span> <span class="trait">DoTheAutoref</span> <span class="keyword">for</span> <span class="builtin_type">u16</span> <span class="brace">{</span> 68<span class="keyword">impl</span> <span class="trait">DoTheAutoref</span> <span class="keyword">for</span> <span class="builtin_type">u16</span> <span class="brace">{</span>
69 <span class="keyword">fn</span> <span class="function declaration associated">calls_autoref</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword declaration">self</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span> 69 <span class="keyword">fn</span> <span class="function declaration associated trait">calls_autoref</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword declaration">self</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span>
70<span class="brace">}</span> 70<span class="brace">}</span>
71 71
72<span class="keyword">fn</span> <span class="function declaration">main</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span> 72<span class="keyword">fn</span> <span class="function declaration">main</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span>
@@ -96,6 +96,6 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
96 <span class="keyword">let</span> <span class="struct">Packed</span> <span class="brace">{</span> <span class="field">a</span><span class="colon">:</span> <span class="keyword unsafe">ref</span> <span class="variable declaration">_a</span> <span class="brace">}</span> <span class="operator">=</span> <span class="variable">packed</span><span class="semicolon">;</span> 96 <span class="keyword">let</span> <span class="struct">Packed</span> <span class="brace">{</span> <span class="field">a</span><span class="colon">:</span> <span class="keyword unsafe">ref</span> <span class="variable declaration">_a</span> <span class="brace">}</span> <span class="operator">=</span> <span class="variable">packed</span><span class="semicolon">;</span>
97 97
98 <span class="comment">// unsafe auto ref of packed field</span> 98 <span class="comment">// unsafe auto ref of packed field</span>
99 <span class="variable">packed</span><span class="operator">.</span><span class="field">a</span><span class="operator">.</span><span class="function associated unsafe">calls_autoref</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span> 99 <span class="variable">packed</span><span class="operator">.</span><span class="field">a</span><span class="operator">.</span><span class="function associated trait unsafe">calls_autoref</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span>
100 <span class="brace">}</span> 100 <span class="brace">}</span>
101<span class="brace">}</span></code></pre> \ No newline at end of file 101<span class="brace">}</span></code></pre> \ No newline at end of file
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlighting.html b/crates/ide/src/syntax_highlighting/test_data/highlighting.html
index 8b2dd3b70..973173254 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlighting.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlighting.html
@@ -41,7 +41,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
41<span class="keyword">mod</span> <span class="module declaration">inner</span> <span class="brace">{</span><span class="brace">}</span> 41<span class="keyword">mod</span> <span class="module declaration">inner</span> <span class="brace">{</span><span class="brace">}</span>
42 42
43<span class="attribute attribute">#</span><span class="attribute attribute">[</span><span class="function attribute">rustc_builtin_macro</span><span class="attribute attribute">]</span> 43<span class="attribute attribute">#</span><span class="attribute attribute">[</span><span class="function attribute">rustc_builtin_macro</span><span class="attribute attribute">]</span>
44<span class="keyword">macro</span> <span class="unresolved_reference declaration">Copy</span> <span class="brace">{</span><span class="brace">}</span> 44<span class="keyword">macro</span> <span class="macro declaration">Copy</span> <span class="brace">{</span><span class="brace">}</span>
45 45
46<span class="comment">// Needed for function consuming vs normal</span> 46<span class="comment">// Needed for function consuming vs normal</span>
47<span class="keyword">pub</span> <span class="keyword">mod</span> <span class="module declaration">marker</span> <span class="brace">{</span> 47<span class="keyword">pub</span> <span class="keyword">mod</span> <span class="module declaration">marker</span> <span class="brace">{</span>
@@ -67,11 +67,11 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
67<span class="brace">}</span> 67<span class="brace">}</span>
68 68
69<span class="keyword">trait</span> <span class="trait declaration">Bar</span> <span class="brace">{</span> 69<span class="keyword">trait</span> <span class="trait declaration">Bar</span> <span class="brace">{</span>
70 <span class="keyword">fn</span> <span class="function declaration associated">bar</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword declaration">self</span><span class="parenthesis">)</span> <span class="operator">-&gt;</span> <span class="builtin_type">i32</span><span class="semicolon">;</span> 70 <span class="keyword">fn</span> <span class="function declaration associated trait">bar</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword declaration">self</span><span class="parenthesis">)</span> <span class="operator">-&gt;</span> <span class="builtin_type">i32</span><span class="semicolon">;</span>
71<span class="brace">}</span> 71<span class="brace">}</span>
72 72
73<span class="keyword">impl</span> <span class="trait">Bar</span> <span class="keyword">for</span> <span class="struct">Foo</span> <span class="brace">{</span> 73<span class="keyword">impl</span> <span class="trait">Bar</span> <span class="keyword">for</span> <span class="struct">Foo</span> <span class="brace">{</span>
74 <span class="keyword">fn</span> <span class="function declaration associated">bar</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword declaration">self</span><span class="parenthesis">)</span> <span class="operator">-&gt;</span> <span class="builtin_type">i32</span> <span class="brace">{</span> 74 <span class="keyword">fn</span> <span class="function declaration associated trait">bar</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword declaration">self</span><span class="parenthesis">)</span> <span class="operator">-&gt;</span> <span class="builtin_type">i32</span> <span class="brace">{</span>
75 <span class="self_keyword">self</span><span class="operator">.</span><span class="field">x</span> 75 <span class="self_keyword">self</span><span class="operator">.</span><span class="field">x</span>
76 <span class="brace">}</span> 76 <span class="brace">}</span>
77<span class="brace">}</span> 77<span class="brace">}</span>
@@ -158,6 +158,16 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
158 <span class="parenthesis">(</span><span class="punctuation">$</span>type<span class="colon">:</span>ty<span class="parenthesis">)</span> <span class="operator">=</span><span class="angle">&gt;</span> <span class="parenthesis">(</span><span class="punctuation">$</span>type<span class="parenthesis">)</span> 158 <span class="parenthesis">(</span><span class="punctuation">$</span>type<span class="colon">:</span>ty<span class="parenthesis">)</span> <span class="operator">=</span><span class="angle">&gt;</span> <span class="parenthesis">(</span><span class="punctuation">$</span>type<span class="parenthesis">)</span>
159<span class="brace">}</span> 159<span class="brace">}</span>
160 160
161<span class="keyword">macro</span> <span class="macro declaration">with_args</span><span class="parenthesis">(</span><span class="punctuation">$</span>i<span class="colon">:</span>ident<span class="parenthesis">)</span> <span class="brace">{</span>
162 <span class="punctuation">$</span>i
163<span class="brace">}</span>
164
165<span class="keyword">macro</span> <span class="macro declaration">without_args</span> <span class="brace">{</span>
166 <span class="parenthesis">(</span><span class="punctuation">$</span>i<span class="colon">:</span>ident<span class="parenthesis">)</span> <span class="operator">=</span><span class="angle">&gt;</span> <span class="brace">{</span>
167 <span class="punctuation">$</span>i
168 <span class="brace">}</span>
169<span class="brace">}</span>
170
161<span class="comment">// comment</span> 171<span class="comment">// comment</span>
162<span class="keyword">fn</span> <span class="function declaration">main</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span> 172<span class="keyword">fn</span> <span class="function declaration">main</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span>
163 <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"Hello, {}!"</span><span class="comma">,</span> <span class="numeric_literal">92</span><span class="parenthesis">)</span><span class="semicolon">;</span> 173 <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"Hello, {}!"</span><span class="comma">,</span> <span class="numeric_literal">92</span><span class="parenthesis">)</span><span class="semicolon">;</span>
diff --git a/crates/ide/src/syntax_highlighting/tests.rs b/crates/ide/src/syntax_highlighting/tests.rs
index 7b2922b0d..369ae0972 100644
--- a/crates/ide/src/syntax_highlighting/tests.rs
+++ b/crates/ide/src/syntax_highlighting/tests.rs
@@ -129,6 +129,16 @@ macro_rules! keyword_frag {
129 ($type:ty) => ($type) 129 ($type:ty) => ($type)
130} 130}
131 131
132macro with_args($i:ident) {
133 $i
134}
135
136macro without_args {
137 ($i:ident) => {
138 $i
139 }
140}
141
132// comment 142// comment
133fn main() { 143fn main() {
134 println!("Hello, {}!", 92); 144 println!("Hello, {}!", 92);
diff --git a/crates/ide/src/syntax_tree.rs b/crates/ide/src/syntax_tree.rs
index 8979de528..633878d1c 100644
--- a/crates/ide/src/syntax_tree.rs
+++ b/crates/ide/src/syntax_tree.rs
@@ -14,6 +14,7 @@ use syntax::{
14// 14//
15// | VS Code | **Rust Analyzer: Show Syntax Tree** 15// | VS Code | **Rust Analyzer: Show Syntax Tree**
16// |=== 16// |===
17// image::https://user-images.githubusercontent.com/48062697/113065586-068bdb80-91b1-11eb-9507-fee67f9f45a0.gif[]
17pub(crate) fn syntax_tree( 18pub(crate) fn syntax_tree(
18 db: &RootDatabase, 19 db: &RootDatabase,
19 file_id: FileId, 20 file_id: FileId,
diff --git a/crates/ide/src/typing/on_enter.rs b/crates/ide/src/typing/on_enter.rs
index 978c479de..9144681bf 100644
--- a/crates/ide/src/typing/on_enter.rs
+++ b/crates/ide/src/typing/on_enter.rs
@@ -32,6 +32,8 @@ use text_edit::TextEdit;
32// "when": "editorTextFocus && !suggestWidgetVisible && editorLangId == rust" 32// "when": "editorTextFocus && !suggestWidgetVisible && editorLangId == rust"
33// } 33// }
34// ---- 34// ----
35//
36// image::https://user-images.githubusercontent.com/48062697/113065578-04c21800-91b1-11eb-82b8-22b8c481e645.gif[]
35pub(crate) fn on_enter(db: &RootDatabase, position: FilePosition) -> Option<TextEdit> { 37pub(crate) fn on_enter(db: &RootDatabase, position: FilePosition) -> Option<TextEdit> {
36 let parse = db.parse(position.file_id); 38 let parse = db.parse(position.file_id);
37 let file = parse.tree(); 39 let file = parse.tree();
diff --git a/crates/ide/src/view_hir.rs b/crates/ide/src/view_hir.rs
index f8f3fae3d..7312afe53 100644
--- a/crates/ide/src/view_hir.rs
+++ b/crates/ide/src/view_hir.rs
@@ -10,6 +10,7 @@ use syntax::{algo::find_node_at_offset, ast, AstNode};
10// 10//
11// | VS Code | **Rust Analyzer: View Hir** 11// | VS Code | **Rust Analyzer: View Hir**
12// |=== 12// |===
13// image::https://user-images.githubusercontent.com/48062697/113065588-068bdb80-91b1-11eb-9a78-0b4ef1e972fb.gif[]
13pub(crate) fn view_hir(db: &RootDatabase, position: FilePosition) -> String { 14pub(crate) fn view_hir(db: &RootDatabase, position: FilePosition) -> String {
14 body_hir(db, position).unwrap_or_else(|| "Not inside a function body".to_string()) 15 body_hir(db, position).unwrap_or_else(|| "Not inside a function body".to_string())
15} 16}