aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_ide
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_ide')
-rw-r--r--crates/ra_ide/src/goto_type_definition.rs22
-rw-r--r--crates/ra_ide/src/inlay_hints.rs5
-rw-r--r--crates/ra_ide/src/join_lines.rs85
-rw-r--r--crates/ra_ide/src/lib.rs2
-rw-r--r--crates/ra_ide/src/references.rs74
-rw-r--r--crates/ra_ide/src/references/rename.rs19
-rw-r--r--crates/ra_ide/src/runnables.rs109
-rw-r--r--crates/ra_ide/src/snapshots/highlighting.html1
-rw-r--r--crates/ra_ide/src/snapshots/rainbow_highlighting.html1
-rw-r--r--crates/ra_ide/src/syntax_highlighting.rs1
10 files changed, 224 insertions, 95 deletions
diff --git a/crates/ra_ide/src/goto_type_definition.rs b/crates/ra_ide/src/goto_type_definition.rs
index 11ad6d137..69940fc36 100644
--- a/crates/ra_ide/src/goto_type_definition.rs
+++ b/crates/ra_ide/src/goto_type_definition.rs
@@ -16,24 +16,16 @@ pub(crate) fn goto_type_definition(
16 let token = pick_best(file.token_at_offset(position.offset))?; 16 let token = pick_best(file.token_at_offset(position.offset))?;
17 let token = descend_into_macros(db, position.file_id, token); 17 let token = descend_into_macros(db, position.file_id, token);
18 18
19 let node = token.value.ancestors().find_map(|token| { 19 let node = token
20 token 20 .value
21 .ancestors() 21 .ancestors()
22 .find(|n| ast::Expr::cast(n.clone()).is_some() || ast::Pat::cast(n.clone()).is_some()) 22 .find(|n| ast::Expr::cast(n.clone()).is_some() || ast::Pat::cast(n.clone()).is_some())?;
23 })?;
24 23
25 let analyzer = hir::SourceAnalyzer::new(db, token.with_value(&node), None); 24 let analyzer = hir::SourceAnalyzer::new(db, token.with_value(&node), None);
26 25
27 let ty: hir::Type = if let Some(ty) = 26 let ty: hir::Type = ast::Expr::cast(node.clone())
28 ast::Expr::cast(node.clone()).and_then(|e| analyzer.type_of(db, &e)) 27 .and_then(|e| analyzer.type_of(db, &e))
29 { 28 .or_else(|| ast::Pat::cast(node.clone()).and_then(|p| analyzer.type_of_pat(db, &p)))?;
30 ty
31 } else if let Some(ty) = ast::Pat::cast(node.clone()).and_then(|p| analyzer.type_of_pat(db, &p))
32 {
33 ty
34 } else {
35 return None;
36 };
37 29
38 let adt_def = ty.autoderef(db).find_map(|ty| ty.as_adt())?; 30 let adt_def = ty.autoderef(db).find_map(|ty| ty.as_adt())?;
39 31
diff --git a/crates/ra_ide/src/inlay_hints.rs b/crates/ra_ide/src/inlay_hints.rs
index 6b0d3d996..2ae97e65f 100644
--- a/crates/ra_ide/src/inlay_hints.rs
+++ b/crates/ra_ide/src/inlay_hints.rs
@@ -80,8 +80,7 @@ fn get_inlay_hints(
80 }, 80 },
81 ast::MatchArmList(it) => { 81 ast::MatchArmList(it) => {
82 it.arms() 82 it.arms()
83 .map(|match_arm| match_arm.pats()) 83 .filter_map(|match_arm| match_arm.pat())
84 .flatten()
85 .for_each(|root_pat| get_pat_type_hints(acc, db, &analyzer, root_pat, true, max_inlay_hint_length)); 84 .for_each(|root_pat| get_pat_type_hints(acc, db, &analyzer, root_pat, true, max_inlay_hint_length));
86 }, 85 },
87 ast::CallExpr(it) => { 86 ast::CallExpr(it) => {
@@ -202,6 +201,7 @@ fn get_leaf_pats(root_pat: ast::Pat) -> Vec<ast::Pat> {
202 Some(pat) => pats_to_process.push_back(pat), 201 Some(pat) => pats_to_process.push_back(pat),
203 _ => leaf_pats.push(maybe_leaf_pat), 202 _ => leaf_pats.push(maybe_leaf_pat),
204 }, 203 },
204 ast::Pat::OrPat(ref_pat) => pats_to_process.extend(ref_pat.pats()),
205 ast::Pat::TuplePat(tuple_pat) => pats_to_process.extend(tuple_pat.args()), 205 ast::Pat::TuplePat(tuple_pat) => pats_to_process.extend(tuple_pat.args()),
206 ast::Pat::RecordPat(record_pat) => { 206 ast::Pat::RecordPat(record_pat) => {
207 if let Some(pat_list) = record_pat.record_field_pat_list() { 207 if let Some(pat_list) = record_pat.record_field_pat_list() {
@@ -222,6 +222,7 @@ fn get_leaf_pats(root_pat: ast::Pat) -> Vec<ast::Pat> {
222 ast::Pat::TupleStructPat(tuple_struct_pat) => { 222 ast::Pat::TupleStructPat(tuple_struct_pat) => {
223 pats_to_process.extend(tuple_struct_pat.args()) 223 pats_to_process.extend(tuple_struct_pat.args())
224 } 224 }
225 ast::Pat::ParenPat(inner_pat) => pats_to_process.extend(inner_pat.pat()),
225 ast::Pat::RefPat(ref_pat) => pats_to_process.extend(ref_pat.pat()), 226 ast::Pat::RefPat(ref_pat) => pats_to_process.extend(ref_pat.pat()),
226 _ => (), 227 _ => (),
227 } 228 }
diff --git a/crates/ra_ide/src/join_lines.rs b/crates/ra_ide/src/join_lines.rs
index 7deeb3494..01fb32b3d 100644
--- a/crates/ra_ide/src/join_lines.rs
+++ b/crates/ra_ide/src/join_lines.rs
@@ -60,36 +60,15 @@ fn remove_newline(edit: &mut TextEditBuilder, token: &SyntaxToken, offset: TextU
60 return; 60 return;
61 } 61 }
62 62
63 // Special case that turns something like:
64 //
65 // ```
66 // my_function({<|>
67 // <some-expr>
68 // })
69 // ```
70 //
71 // into `my_function(<some-expr>)`
72 if join_single_expr_block(edit, token).is_some() {
73 return;
74 }
75 // ditto for
76 //
77 // ```
78 // use foo::{<|>
79 // bar
80 // };
81 // ```
82 if join_single_use_tree(edit, token).is_some() {
83 return;
84 }
85
86 // The node is between two other nodes 63 // The node is between two other nodes
87 let prev = token.prev_sibling_or_token().unwrap(); 64 let prev = token.prev_sibling_or_token().unwrap();
88 let next = token.next_sibling_or_token().unwrap(); 65 let next = token.next_sibling_or_token().unwrap();
89 if is_trailing_comma(prev.kind(), next.kind()) { 66 if is_trailing_comma(prev.kind(), next.kind()) {
90 // Removes: trailing comma, newline (incl. surrounding whitespace) 67 // Removes: trailing comma, newline (incl. surrounding whitespace)
91 edit.delete(TextRange::from_to(prev.text_range().start(), token.text_range().end())); 68 edit.delete(TextRange::from_to(prev.text_range().start(), token.text_range().end()));
92 } else if prev.kind() == T![,] && next.kind() == T!['}'] { 69 return;
70 }
71 if prev.kind() == T![,] && next.kind() == T!['}'] {
93 // Removes: comma, newline (incl. surrounding whitespace) 72 // Removes: comma, newline (incl. surrounding whitespace)
94 let space = if let Some(left) = prev.prev_sibling_or_token() { 73 let space = if let Some(left) = prev.prev_sibling_or_token() {
95 compute_ws(left.kind(), next.kind()) 74 compute_ws(left.kind(), next.kind())
@@ -100,7 +79,10 @@ fn remove_newline(edit: &mut TextEditBuilder, token: &SyntaxToken, offset: TextU
100 TextRange::from_to(prev.text_range().start(), token.text_range().end()), 79 TextRange::from_to(prev.text_range().start(), token.text_range().end()),
101 space.to_string(), 80 space.to_string(),
102 ); 81 );
103 } else if let (Some(_), Some(next)) = ( 82 return;
83 }
84
85 if let (Some(_), Some(next)) = (
104 prev.as_token().cloned().and_then(ast::Comment::cast), 86 prev.as_token().cloned().and_then(ast::Comment::cast),
105 next.as_token().cloned().and_then(ast::Comment::cast), 87 next.as_token().cloned().and_then(ast::Comment::cast),
106 ) { 88 ) {
@@ -109,10 +91,34 @@ fn remove_newline(edit: &mut TextEditBuilder, token: &SyntaxToken, offset: TextU
109 token.text_range().start(), 91 token.text_range().start(),
110 next.syntax().text_range().start() + TextUnit::of_str(next.prefix()), 92 next.syntax().text_range().start() + TextUnit::of_str(next.prefix()),
111 )); 93 ));
112 } else { 94 return;
113 // Remove newline but add a computed amount of whitespace characters 95 }
114 edit.replace(token.text_range(), compute_ws(prev.kind(), next.kind()).to_string()); 96
97 // Special case that turns something like:
98 //
99 // ```
100 // my_function({<|>
101 // <some-expr>
102 // })
103 // ```
104 //
105 // into `my_function(<some-expr>)`
106 if join_single_expr_block(edit, token).is_some() {
107 return;
115 } 108 }
109 // ditto for
110 //
111 // ```
112 // use foo::{<|>
113 // bar
114 // };
115 // ```
116 if join_single_use_tree(edit, token).is_some() {
117 return;
118 }
119
120 // Remove newline but add a computed amount of whitespace characters
121 edit.replace(token.text_range(), compute_ws(prev.kind(), next.kind()).to_string());
116} 122}
117 123
118fn has_comma_after(node: &SyntaxNode) -> bool { 124fn has_comma_after(node: &SyntaxNode) -> bool {
@@ -608,4 +614,27 @@ pub fn handle_find_matching_brace() {
608}", 614}",
609 ); 615 );
610 } 616 }
617
618 #[test]
619 fn test_join_lines_commented_block() {
620 check_join_lines(
621 r"
622fn main() {
623 let _ = {
624 // <|>foo
625 // bar
626 92
627 };
628}
629 ",
630 r"
631fn main() {
632 let _ = {
633 // <|>foo bar
634 92
635 };
636}
637 ",
638 )
639 }
611} 640}
diff --git a/crates/ra_ide/src/lib.rs b/crates/ra_ide/src/lib.rs
index 689921f3f..9d66c365b 100644
--- a/crates/ra_ide/src/lib.rs
+++ b/crates/ra_ide/src/lib.rs
@@ -71,7 +71,7 @@ pub use crate::{
71 references::{ 71 references::{
72 Declaration, Reference, ReferenceAccess, ReferenceKind, ReferenceSearchResult, SearchScope, 72 Declaration, Reference, ReferenceAccess, ReferenceKind, ReferenceSearchResult, SearchScope,
73 }, 73 },
74 runnables::{Runnable, RunnableKind}, 74 runnables::{Runnable, RunnableKind, TestId},
75 source_change::{FileSystemEdit, SourceChange, SourceFileEdit}, 75 source_change::{FileSystemEdit, SourceChange, SourceFileEdit},
76 syntax_highlighting::HighlightedRange, 76 syntax_highlighting::HighlightedRange,
77}; 77};
diff --git a/crates/ra_ide/src/references.rs b/crates/ra_ide/src/references.rs
index a6320bd2f..de924fad2 100644
--- a/crates/ra_ide/src/references.rs
+++ b/crates/ra_ide/src/references.rs
@@ -13,6 +13,7 @@ mod classify;
13mod rename; 13mod rename;
14mod search_scope; 14mod search_scope;
15 15
16use crate::expand::descend_into_macros_with_analyzer;
16use hir::{InFile, SourceBinder}; 17use hir::{InFile, SourceBinder};
17use once_cell::unsync::Lazy; 18use once_cell::unsync::Lazy;
18use ra_db::{SourceDatabase, SourceDatabaseExt}; 19use ra_db::{SourceDatabase, SourceDatabaseExt};
@@ -192,39 +193,62 @@ fn process_definition(
192 193
193 let parse = Lazy::new(|| SourceFile::parse(&text)); 194 let parse = Lazy::new(|| SourceFile::parse(&text));
194 let mut sb = Lazy::new(|| SourceBinder::new(db)); 195 let mut sb = Lazy::new(|| SourceBinder::new(db));
196 let mut analyzer = None;
195 197
196 for (idx, _) in text.match_indices(pat) { 198 for (idx, _) in text.match_indices(pat) {
197 let offset = TextUnit::from_usize(idx); 199 let offset = TextUnit::from_usize(idx);
198 200
199 if let Some(name_ref) = 201 let (name_ref, range) = if let Some(name_ref) =
200 find_node_at_offset::<ast::NameRef>(parse.tree().syntax(), offset) 202 find_node_at_offset::<ast::NameRef>(parse.tree().syntax(), offset)
201 { 203 {
202 let range = name_ref.syntax().text_range(); 204 let range = name_ref.syntax().text_range();
203 if let Some(search_range) = search_range { 205 (InFile::new(file_id.into(), name_ref), range)
204 if !range.is_subrange(&search_range) { 206 } else {
205 continue; 207 // Handle macro token cases
206 } 208 let t = match parse.tree().syntax().token_at_offset(offset) {
209 TokenAtOffset::None => continue,
210 TokenAtOffset::Single(t) => t,
211 TokenAtOffset::Between(_, t) => t,
212 };
213 let range = t.text_range();
214 let analyzer = analyzer.get_or_insert_with(|| {
215 sb.analyze(InFile::new(file_id.into(), parse.tree().syntax()), None)
216 });
217 let expanded = descend_into_macros_with_analyzer(
218 db,
219 &analyzer,
220 InFile::new(file_id.into(), t),
221 );
222 if let Some(token) = ast::NameRef::cast(expanded.value.parent()) {
223 (expanded.with_value(token), range)
224 } else {
225 continue;
207 } 226 }
208 // FIXME: reuse sb 227 };
209 // See https://github.com/rust-lang/rust/pull/68198#issuecomment-574269098 228
210 229 if let Some(search_range) = search_range {
211 if let Some(d) = classify_name_ref(&mut sb, InFile::new(file_id.into(), &name_ref)) 230 if !range.is_subrange(&search_range) {
212 { 231 continue;
213 if d == def { 232 }
214 let kind = if is_record_lit_name_ref(&name_ref) 233 }
215 || is_call_expr_name_ref(&name_ref) 234 // FIXME: reuse sb
216 { 235 // See https://github.com/rust-lang/rust/pull/68198#issuecomment-574269098
217 ReferenceKind::StructLiteral 236
218 } else { 237 if let Some(d) = classify_name_ref(&mut sb, name_ref.as_ref()) {
219 ReferenceKind::Other 238 if d == def {
220 }; 239 let kind = if is_record_lit_name_ref(&name_ref.value)
221 240 || is_call_expr_name_ref(&name_ref.value)
222 refs.push(Reference { 241 {
223 file_range: FileRange { file_id, range }, 242 ReferenceKind::StructLiteral
224 kind, 243 } else {
225 access: reference_access(&d.kind, &name_ref), 244 ReferenceKind::Other
226 }); 245 };
227 } 246
247 refs.push(Reference {
248 file_range: FileRange { file_id, range },
249 kind,
250 access: reference_access(&d.kind, &name_ref.value),
251 });
228 } 252 }
229 } 253 }
230 } 254 }
diff --git a/crates/ra_ide/src/references/rename.rs b/crates/ra_ide/src/references/rename.rs
index 08e77c01f..c46b78cb6 100644
--- a/crates/ra_ide/src/references/rename.rs
+++ b/crates/ra_ide/src/references/rename.rs
@@ -211,6 +211,25 @@ mod tests {
211 } 211 }
212 212
213 #[test] 213 #[test]
214 fn test_rename_for_macro_args() {
215 test_rename(
216 r#"
217 macro_rules! foo {($i:ident) => {$i} }
218 fn main() {
219 let a<|> = "test";
220 foo!(a);
221 }"#,
222 "b",
223 r#"
224 macro_rules! foo {($i:ident) => {$i} }
225 fn main() {
226 let b = "test";
227 foo!(b);
228 }"#,
229 );
230 }
231
232 #[test]
214 fn test_rename_for_param_inside() { 233 fn test_rename_for_param_inside() {
215 test_rename( 234 test_rename(
216 r#" 235 r#"
diff --git a/crates/ra_ide/src/runnables.rs b/crates/ra_ide/src/runnables.rs
index b6b0c70f9..be2a67d0a 100644
--- a/crates/ra_ide/src/runnables.rs
+++ b/crates/ra_ide/src/runnables.rs
@@ -1,6 +1,6 @@
1//! FIXME: write short doc here 1//! FIXME: write short doc here
2 2
3use hir::InFile; 3use hir::{InFile, SourceBinder};
4use itertools::Itertools; 4use itertools::Itertools;
5use ra_db::SourceDatabase; 5use ra_db::SourceDatabase;
6use ra_ide_db::RootDatabase; 6use ra_ide_db::RootDatabase;
@@ -10,6 +10,7 @@ use ra_syntax::{
10}; 10};
11 11
12use crate::FileId; 12use crate::FileId;
13use std::fmt::Display;
13 14
14#[derive(Debug)] 15#[derive(Debug)]
15pub struct Runnable { 16pub struct Runnable {
@@ -18,38 +19,84 @@ pub struct Runnable {
18} 19}
19 20
20#[derive(Debug)] 21#[derive(Debug)]
22pub enum TestId {
23 Name(String),
24 Path(String),
25}
26
27impl Display for TestId {
28 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
29 match self {
30 TestId::Name(name) => write!(f, "{}", name),
31 TestId::Path(path) => write!(f, "{}", path),
32 }
33 }
34}
35
36#[derive(Debug)]
21pub enum RunnableKind { 37pub enum RunnableKind {
22 Test { name: String }, 38 Test { test_id: TestId },
23 TestMod { path: String }, 39 TestMod { path: String },
24 Bench { name: String }, 40 Bench { test_id: TestId },
25 Bin, 41 Bin,
26} 42}
27 43
28pub(crate) fn runnables(db: &RootDatabase, file_id: FileId) -> Vec<Runnable> { 44pub(crate) fn runnables(db: &RootDatabase, file_id: FileId) -> Vec<Runnable> {
29 let parse = db.parse(file_id); 45 let parse = db.parse(file_id);
30 parse.tree().syntax().descendants().filter_map(|i| runnable(db, file_id, i)).collect() 46 let mut sb = SourceBinder::new(db);
47 parse.tree().syntax().descendants().filter_map(|i| runnable(db, &mut sb, file_id, i)).collect()
31} 48}
32 49
33fn runnable(db: &RootDatabase, file_id: FileId, item: SyntaxNode) -> Option<Runnable> { 50fn runnable(
51 db: &RootDatabase,
52 source_binder: &mut SourceBinder<RootDatabase>,
53 file_id: FileId,
54 item: SyntaxNode,
55) -> Option<Runnable> {
34 match_ast! { 56 match_ast! {
35 match item { 57 match item {
36 ast::FnDef(it) => { runnable_fn(it) }, 58 ast::FnDef(it) => { runnable_fn(db, source_binder, file_id, it) },
37 ast::Module(it) => { runnable_mod(db, file_id, it) }, 59 ast::Module(it) => { runnable_mod(db, source_binder, file_id, it) },
38 _ => { None }, 60 _ => { None },
39 } 61 }
40 } 62 }
41} 63}
42 64
43fn runnable_fn(fn_def: ast::FnDef) -> Option<Runnable> { 65fn runnable_fn(
44 let name = fn_def.name()?.text().clone(); 66 db: &RootDatabase,
45 let kind = if name == "main" { 67 source_binder: &mut SourceBinder<RootDatabase>,
68 file_id: FileId,
69 fn_def: ast::FnDef,
70) -> Option<Runnable> {
71 let name_string = fn_def.name()?.text().to_string();
72
73 let kind = if name_string == "main" {
46 RunnableKind::Bin 74 RunnableKind::Bin
47 } else if has_test_related_attribute(&fn_def) {
48 RunnableKind::Test { name: name.to_string() }
49 } else if fn_def.has_atom_attr("bench") {
50 RunnableKind::Bench { name: name.to_string() }
51 } else { 75 } else {
52 return None; 76 let test_id = if let Some(module) = source_binder
77 .to_def(InFile::new(file_id.into(), fn_def.clone()))
78 .map(|def| def.module(db))
79 {
80 let path = module
81 .path_to_root(db)
82 .into_iter()
83 .rev()
84 .filter_map(|it| it.name(db))
85 .map(|name| name.to_string())
86 .chain(std::iter::once(name_string))
87 .join("::");
88 TestId::Path(path)
89 } else {
90 TestId::Name(name_string)
91 };
92
93 if has_test_related_attribute(&fn_def) {
94 RunnableKind::Test { test_id }
95 } else if fn_def.has_atom_attr("bench") {
96 RunnableKind::Bench { test_id }
97 } else {
98 return None;
99 }
53 }; 100 };
54 Some(Runnable { range: fn_def.syntax().text_range(), kind }) 101 Some(Runnable { range: fn_def.syntax().text_range(), kind })
55} 102}
@@ -68,7 +115,12 @@ fn has_test_related_attribute(fn_def: &ast::FnDef) -> bool {
68 .any(|attribute_text| attribute_text.contains("test")) 115 .any(|attribute_text| attribute_text.contains("test"))
69} 116}
70 117
71fn runnable_mod(db: &RootDatabase, file_id: FileId, module: ast::Module) -> Option<Runnable> { 118fn runnable_mod(
119 db: &RootDatabase,
120 source_binder: &mut SourceBinder<RootDatabase>,
121 file_id: FileId,
122 module: ast::Module,
123) -> Option<Runnable> {
72 let has_test_function = module 124 let has_test_function = module
73 .item_list()? 125 .item_list()?
74 .items() 126 .items()
@@ -76,13 +128,12 @@ fn runnable_mod(db: &RootDatabase, file_id: FileId, module: ast::Module) -> Opti
76 ast::ModuleItem::FnDef(it) => Some(it), 128 ast::ModuleItem::FnDef(it) => Some(it),
77 _ => None, 129 _ => None,
78 }) 130 })
79 .any(|f| f.has_atom_attr("test")); 131 .any(|f| has_test_related_attribute(&f));
80 if !has_test_function { 132 if !has_test_function {
81 return None; 133 return None;
82 } 134 }
83 let range = module.syntax().text_range(); 135 let range = module.syntax().text_range();
84 let mut sb = hir::SourceBinder::new(db); 136 let module = source_binder.to_def(InFile::new(file_id.into(), module))?;
85 let module = sb.to_def(InFile::new(file_id.into(), module))?;
86 137
87 let path = module.path_to_root(db).into_iter().rev().filter_map(|it| it.name(db)).join("::"); 138 let path = module.path_to_root(db).into_iter().rev().filter_map(|it| it.name(db)).join("::");
88 Some(Runnable { range, kind: RunnableKind::TestMod { path } }) 139 Some(Runnable { range, kind: RunnableKind::TestMod { path } })
@@ -121,13 +172,17 @@ mod tests {
121 Runnable { 172 Runnable {
122 range: [22; 46), 173 range: [22; 46),
123 kind: Test { 174 kind: Test {
124 name: "test_foo", 175 test_id: Path(
176 "test_foo",
177 ),
125 }, 178 },
126 }, 179 },
127 Runnable { 180 Runnable {
128 range: [47; 81), 181 range: [47; 81),
129 kind: Test { 182 kind: Test {
130 name: "test_foo", 183 test_id: Path(
184 "test_foo",
185 ),
131 }, 186 },
132 }, 187 },
133 ] 188 ]
@@ -160,7 +215,9 @@ mod tests {
160 Runnable { 215 Runnable {
161 range: [28; 57), 216 range: [28; 57),
162 kind: Test { 217 kind: Test {
163 name: "test_foo1", 218 test_id: Path(
219 "test_mod::test_foo1",
220 ),
164 }, 221 },
165 }, 222 },
166 ] 223 ]
@@ -195,7 +252,9 @@ mod tests {
195 Runnable { 252 Runnable {
196 range: [46; 79), 253 range: [46; 79),
197 kind: Test { 254 kind: Test {
198 name: "test_foo1", 255 test_id: Path(
256 "foo::test_mod::test_foo1",
257 ),
199 }, 258 },
200 }, 259 },
201 ] 260 ]
@@ -232,7 +291,9 @@ mod tests {
232 Runnable { 291 Runnable {
233 range: [68; 105), 292 range: [68; 105),
234 kind: Test { 293 kind: Test {
235 name: "test_foo1", 294 test_id: Path(
295 "foo::bar::test_mod::test_foo1",
296 ),
236 }, 297 },
237 }, 298 },
238 ] 299 ]
diff --git a/crates/ra_ide/src/snapshots/highlighting.html b/crates/ra_ide/src/snapshots/highlighting.html
index 1cc55e78b..a02dbaf2f 100644
--- a/crates/ra_ide/src/snapshots/highlighting.html
+++ b/crates/ra_ide/src/snapshots/highlighting.html
@@ -16,6 +16,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
16.literal { color: #BFEBBF; } 16.literal { color: #BFEBBF; }
17.literal\.numeric { color: #6A8759; } 17.literal\.numeric { color: #6A8759; }
18.macro { color: #94BFF3; } 18.macro { color: #94BFF3; }
19.module { color: #AFD8AF; }
19.variable { color: #DCDCCC; } 20.variable { color: #DCDCCC; }
20.variable\.mut { color: #DCDCCC; text-decoration: underline; } 21.variable\.mut { color: #DCDCCC; text-decoration: underline; }
21 22
diff --git a/crates/ra_ide/src/snapshots/rainbow_highlighting.html b/crates/ra_ide/src/snapshots/rainbow_highlighting.html
index 918fd4b97..95f038f00 100644
--- a/crates/ra_ide/src/snapshots/rainbow_highlighting.html
+++ b/crates/ra_ide/src/snapshots/rainbow_highlighting.html
@@ -16,6 +16,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
16.literal { color: #BFEBBF; } 16.literal { color: #BFEBBF; }
17.literal\.numeric { color: #6A8759; } 17.literal\.numeric { color: #6A8759; }
18.macro { color: #94BFF3; } 18.macro { color: #94BFF3; }
19.module { color: #AFD8AF; }
19.variable { color: #DCDCCC; } 20.variable { color: #DCDCCC; }
20.variable\.mut { color: #DCDCCC; text-decoration: underline; } 21.variable\.mut { color: #DCDCCC; text-decoration: underline; }
21 22
diff --git a/crates/ra_ide/src/syntax_highlighting.rs b/crates/ra_ide/src/syntax_highlighting.rs
index 174e13595..20c414ca1 100644
--- a/crates/ra_ide/src/syntax_highlighting.rs
+++ b/crates/ra_ide/src/syntax_highlighting.rs
@@ -365,6 +365,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
365.literal { color: #BFEBBF; } 365.literal { color: #BFEBBF; }
366.literal\\.numeric { color: #6A8759; } 366.literal\\.numeric { color: #6A8759; }
367.macro { color: #94BFF3; } 367.macro { color: #94BFF3; }
368.module { color: #AFD8AF; }
368.variable { color: #DCDCCC; } 369.variable { color: #DCDCCC; }
369.variable\\.mut { color: #DCDCCC; text-decoration: underline; } 370.variable\\.mut { color: #DCDCCC; text-decoration: underline; }
370 371