aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
Diffstat (limited to 'crates')
-rw-r--r--crates/ra_assists/src/assist_context.rs2
-rw-r--r--crates/ra_assists/src/handlers/replace_qualified_name_with_use.rs280
-rw-r--r--crates/ra_assists/src/utils.rs2
-rw-r--r--crates/ra_assists/src/utils/insert_use.rs24
-rw-r--r--crates/ra_ide/src/lib.rs6
-rw-r--r--crates/ra_ide/src/prime_caches.rs2
-rw-r--r--crates/ra_ide/src/snapshots/highlight_doctest.html23
-rw-r--r--crates/ra_ide/src/snapshots/highlight_injection.html1
-rw-r--r--crates/ra_ide/src/snapshots/highlight_strings.html1
-rw-r--r--crates/ra_ide/src/snapshots/highlight_unsafe.html1
-rw-r--r--crates/ra_ide/src/snapshots/highlighting.html9
-rw-r--r--crates/ra_ide/src/snapshots/rainbow_highlighting.html1
-rw-r--r--crates/ra_ide/src/syntax_highlighting.rs100
-rw-r--r--crates/ra_ide/src/syntax_highlighting/html.rs3
-rw-r--r--crates/ra_ide/src/syntax_highlighting/injection.rs2
-rw-r--r--crates/ra_ide/src/syntax_highlighting/tests.rs22
-rw-r--r--crates/ra_project_model/src/lib.rs32
-rw-r--r--crates/ra_syntax/src/algo.rs8
-rw-r--r--crates/ra_syntax/src/lib.rs3
-rw-r--r--crates/rust-analyzer/src/bin/main.rs8
-rw-r--r--crates/rust-analyzer/src/config.rs6
-rw-r--r--crates/rust-analyzer/src/main_loop.rs7
22 files changed, 429 insertions, 114 deletions
diff --git a/crates/ra_assists/src/assist_context.rs b/crates/ra_assists/src/assist_context.rs
index edd8255f4..ee614de72 100644
--- a/crates/ra_assists/src/assist_context.rs
+++ b/crates/ra_assists/src/assist_context.rs
@@ -252,7 +252,7 @@ impl AssistBuilder {
252 pub(crate) fn rewrite(&mut self, rewriter: SyntaxRewriter) { 252 pub(crate) fn rewrite(&mut self, rewriter: SyntaxRewriter) {
253 let node = rewriter.rewrite_root().unwrap(); 253 let node = rewriter.rewrite_root().unwrap();
254 let new = rewriter.rewrite(&node); 254 let new = rewriter.rewrite(&node);
255 algo::diff(&node, &new).into_text_edit(&mut self.edit) 255 algo::diff(&node, &new).into_text_edit(&mut self.edit);
256 } 256 }
257 257
258 // FIXME: kill this API 258 // FIXME: kill this API
diff --git a/crates/ra_assists/src/handlers/replace_qualified_name_with_use.rs b/crates/ra_assists/src/handlers/replace_qualified_name_with_use.rs
index 0197a8cf0..b4784c333 100644
--- a/crates/ra_assists/src/handlers/replace_qualified_name_with_use.rs
+++ b/crates/ra_assists/src/handlers/replace_qualified_name_with_use.rs
@@ -1,7 +1,10 @@
1use hir; 1use hir;
2use ra_syntax::{ast, AstNode, SmolStr, TextRange}; 2use ra_syntax::{algo::SyntaxRewriter, ast, match_ast, AstNode, SmolStr, SyntaxNode};
3 3
4use crate::{utils::insert_use_statement, AssistContext, AssistId, Assists}; 4use crate::{
5 utils::{find_insert_use_container, insert_use_statement},
6 AssistContext, AssistId, Assists,
7};
5 8
6// Assist: replace_qualified_name_with_use 9// Assist: replace_qualified_name_with_use
7// 10//
@@ -39,16 +42,18 @@ pub(crate) fn replace_qualified_name_with_use(
39 target, 42 target,
40 |builder| { 43 |builder| {
41 let path_to_import = hir_path.mod_path().clone(); 44 let path_to_import = hir_path.mod_path().clone();
45 let container = match find_insert_use_container(path.syntax(), ctx) {
46 Some(c) => c,
47 None => return,
48 };
42 insert_use_statement(path.syntax(), &path_to_import, ctx, builder.text_edit_builder()); 49 insert_use_statement(path.syntax(), &path_to_import, ctx, builder.text_edit_builder());
43 50
44 if let Some(last) = path.segment() { 51 // Now that we've brought the name into scope, re-qualify all paths that could be
45 // Here we are assuming the assist will provide a correct use statement 52 // affected (that is, all paths inside the node we added the `use` to).
46 // so we can delete the path qualifier 53 let mut rewriter = SyntaxRewriter::default();
47 builder.delete(TextRange::new( 54 let syntax = container.either(|l| l.syntax().clone(), |r| r.syntax().clone());
48 path.syntax().text_range().start(), 55 shorten_paths(&mut rewriter, syntax, path);
49 last.syntax().text_range().start(), 56 builder.rewrite(rewriter);
50 ));
51 }
52 }, 57 },
53 ) 58 )
54} 59}
@@ -73,6 +78,69 @@ fn collect_hir_path_segments(path: &hir::Path) -> Option<Vec<SmolStr>> {
73 Some(ps) 78 Some(ps)
74} 79}
75 80
81/// Adds replacements to `re` that shorten `path` in all descendants of `node`.
82fn shorten_paths(rewriter: &mut SyntaxRewriter<'static>, node: SyntaxNode, path: ast::Path) {
83 for child in node.children() {
84 match_ast! {
85 match child {
86 // Don't modify `use` items, as this can break the `use` item when injecting a new
87 // import into the use tree.
88 ast::UseItem(_it) => continue,
89 // Don't descend into submodules, they don't have the same `use` items in scope.
90 ast::Module(_it) => continue,
91
92 ast::Path(p) => {
93 match maybe_replace_path(rewriter, p.clone(), path.clone()) {
94 Some(()) => {},
95 None => shorten_paths(rewriter, p.syntax().clone(), path.clone()),
96 }
97 },
98 _ => shorten_paths(rewriter, child, path.clone()),
99 }
100 }
101 }
102}
103
104fn maybe_replace_path(
105 rewriter: &mut SyntaxRewriter<'static>,
106 path: ast::Path,
107 target: ast::Path,
108) -> Option<()> {
109 if !path_eq(path.clone(), target.clone()) {
110 return None;
111 }
112
113 // Shorten `path`, leaving only its last segment.
114 if let Some(parent) = path.qualifier() {
115 rewriter.delete(parent.syntax());
116 }
117 if let Some(double_colon) = path.coloncolon_token() {
118 rewriter.delete(&double_colon);
119 }
120
121 Some(())
122}
123
124fn path_eq(lhs: ast::Path, rhs: ast::Path) -> bool {
125 let mut lhs_curr = lhs;
126 let mut rhs_curr = rhs;
127 loop {
128 match (lhs_curr.segment(), rhs_curr.segment()) {
129 (Some(lhs), Some(rhs)) if lhs.syntax().text() == rhs.syntax().text() => (),
130 _ => return false,
131 }
132
133 match (lhs_curr.qualifier(), rhs_curr.qualifier()) {
134 (Some(lhs), Some(rhs)) => {
135 lhs_curr = lhs;
136 rhs_curr = rhs;
137 }
138 (None, None) => return true,
139 _ => return false,
140 }
141 }
142}
143
76#[cfg(test)] 144#[cfg(test)]
77mod tests { 145mod tests {
78 use crate::tests::{check_assist, check_assist_not_applicable}; 146 use crate::tests::{check_assist, check_assist_not_applicable};
@@ -83,10 +151,10 @@ mod tests {
83 fn test_replace_add_use_no_anchor() { 151 fn test_replace_add_use_no_anchor() {
84 check_assist( 152 check_assist(
85 replace_qualified_name_with_use, 153 replace_qualified_name_with_use,
86 " 154 r"
87std::fmt::Debug<|> 155std::fmt::Debug<|>
88 ", 156 ",
89 " 157 r"
90use std::fmt::Debug; 158use std::fmt::Debug;
91 159
92Debug 160Debug
@@ -97,13 +165,13 @@ Debug
97 fn test_replace_add_use_no_anchor_with_item_below() { 165 fn test_replace_add_use_no_anchor_with_item_below() {
98 check_assist( 166 check_assist(
99 replace_qualified_name_with_use, 167 replace_qualified_name_with_use,
100 " 168 r"
101std::fmt::Debug<|> 169std::fmt::Debug<|>
102 170
103fn main() { 171fn main() {
104} 172}
105 ", 173 ",
106 " 174 r"
107use std::fmt::Debug; 175use std::fmt::Debug;
108 176
109Debug 177Debug
@@ -118,13 +186,13 @@ fn main() {
118 fn test_replace_add_use_no_anchor_with_item_above() { 186 fn test_replace_add_use_no_anchor_with_item_above() {
119 check_assist( 187 check_assist(
120 replace_qualified_name_with_use, 188 replace_qualified_name_with_use,
121 " 189 r"
122fn main() { 190fn main() {
123} 191}
124 192
125std::fmt::Debug<|> 193std::fmt::Debug<|>
126 ", 194 ",
127 " 195 r"
128use std::fmt::Debug; 196use std::fmt::Debug;
129 197
130fn main() { 198fn main() {
@@ -139,10 +207,10 @@ Debug
139 fn test_replace_add_use_no_anchor_2seg() { 207 fn test_replace_add_use_no_anchor_2seg() {
140 check_assist( 208 check_assist(
141 replace_qualified_name_with_use, 209 replace_qualified_name_with_use,
142 " 210 r"
143std::fmt<|>::Debug 211std::fmt<|>::Debug
144 ", 212 ",
145 " 213 r"
146use std::fmt; 214use std::fmt;
147 215
148fmt::Debug 216fmt::Debug
@@ -154,13 +222,13 @@ fmt::Debug
154 fn test_replace_add_use() { 222 fn test_replace_add_use() {
155 check_assist( 223 check_assist(
156 replace_qualified_name_with_use, 224 replace_qualified_name_with_use,
157 " 225 r"
158use stdx; 226use stdx;
159 227
160impl std::fmt::Debug<|> for Foo { 228impl std::fmt::Debug<|> for Foo {
161} 229}
162 ", 230 ",
163 " 231 r"
164use stdx; 232use stdx;
165use std::fmt::Debug; 233use std::fmt::Debug;
166 234
@@ -174,11 +242,11 @@ impl Debug for Foo {
174 fn test_replace_file_use_other_anchor() { 242 fn test_replace_file_use_other_anchor() {
175 check_assist( 243 check_assist(
176 replace_qualified_name_with_use, 244 replace_qualified_name_with_use,
177 " 245 r"
178impl std::fmt::Debug<|> for Foo { 246impl std::fmt::Debug<|> for Foo {
179} 247}
180 ", 248 ",
181 " 249 r"
182use std::fmt::Debug; 250use std::fmt::Debug;
183 251
184impl Debug for Foo { 252impl Debug for Foo {
@@ -191,11 +259,11 @@ impl Debug for Foo {
191 fn test_replace_add_use_other_anchor_indent() { 259 fn test_replace_add_use_other_anchor_indent() {
192 check_assist( 260 check_assist(
193 replace_qualified_name_with_use, 261 replace_qualified_name_with_use,
194 " 262 r"
195 impl std::fmt::Debug<|> for Foo { 263 impl std::fmt::Debug<|> for Foo {
196 } 264 }
197 ", 265 ",
198 " 266 r"
199 use std::fmt::Debug; 267 use std::fmt::Debug;
200 268
201 impl Debug for Foo { 269 impl Debug for Foo {
@@ -208,13 +276,13 @@ impl Debug for Foo {
208 fn test_replace_split_different() { 276 fn test_replace_split_different() {
209 check_assist( 277 check_assist(
210 replace_qualified_name_with_use, 278 replace_qualified_name_with_use,
211 " 279 r"
212use std::fmt; 280use std::fmt;
213 281
214impl std::io<|> for Foo { 282impl std::io<|> for Foo {
215} 283}
216 ", 284 ",
217 " 285 r"
218use std::{io, fmt}; 286use std::{io, fmt};
219 287
220impl io for Foo { 288impl io for Foo {
@@ -227,13 +295,13 @@ impl io for Foo {
227 fn test_replace_split_self_for_use() { 295 fn test_replace_split_self_for_use() {
228 check_assist( 296 check_assist(
229 replace_qualified_name_with_use, 297 replace_qualified_name_with_use,
230 " 298 r"
231use std::fmt; 299use std::fmt;
232 300
233impl std::fmt::Debug<|> for Foo { 301impl std::fmt::Debug<|> for Foo {
234} 302}
235 ", 303 ",
236 " 304 r"
237use std::fmt::{self, Debug, }; 305use std::fmt::{self, Debug, };
238 306
239impl Debug for Foo { 307impl Debug for Foo {
@@ -246,13 +314,13 @@ impl Debug for Foo {
246 fn test_replace_split_self_for_target() { 314 fn test_replace_split_self_for_target() {
247 check_assist( 315 check_assist(
248 replace_qualified_name_with_use, 316 replace_qualified_name_with_use,
249 " 317 r"
250use std::fmt::Debug; 318use std::fmt::Debug;
251 319
252impl std::fmt<|> for Foo { 320impl std::fmt<|> for Foo {
253} 321}
254 ", 322 ",
255 " 323 r"
256use std::fmt::{self, Debug}; 324use std::fmt::{self, Debug};
257 325
258impl fmt for Foo { 326impl fmt for Foo {
@@ -265,13 +333,13 @@ impl fmt for Foo {
265 fn test_replace_add_to_nested_self_nested() { 333 fn test_replace_add_to_nested_self_nested() {
266 check_assist( 334 check_assist(
267 replace_qualified_name_with_use, 335 replace_qualified_name_with_use,
268 " 336 r"
269use std::fmt::{Debug, nested::{Display}}; 337use std::fmt::{Debug, nested::{Display}};
270 338
271impl std::fmt::nested<|> for Foo { 339impl std::fmt::nested<|> for Foo {
272} 340}
273", 341",
274 " 342 r"
275use std::fmt::{Debug, nested::{Display, self}}; 343use std::fmt::{Debug, nested::{Display, self}};
276 344
277impl nested for Foo { 345impl nested for Foo {
@@ -284,13 +352,13 @@ impl nested for Foo {
284 fn test_replace_add_to_nested_self_already_included() { 352 fn test_replace_add_to_nested_self_already_included() {
285 check_assist( 353 check_assist(
286 replace_qualified_name_with_use, 354 replace_qualified_name_with_use,
287 " 355 r"
288use std::fmt::{Debug, nested::{self, Display}}; 356use std::fmt::{Debug, nested::{self, Display}};
289 357
290impl std::fmt::nested<|> for Foo { 358impl std::fmt::nested<|> for Foo {
291} 359}
292", 360",
293 " 361 r"
294use std::fmt::{Debug, nested::{self, Display}}; 362use std::fmt::{Debug, nested::{self, Display}};
295 363
296impl nested for Foo { 364impl nested for Foo {
@@ -303,13 +371,13 @@ impl nested for Foo {
303 fn test_replace_add_to_nested_nested() { 371 fn test_replace_add_to_nested_nested() {
304 check_assist( 372 check_assist(
305 replace_qualified_name_with_use, 373 replace_qualified_name_with_use,
306 " 374 r"
307use std::fmt::{Debug, nested::{Display}}; 375use std::fmt::{Debug, nested::{Display}};
308 376
309impl std::fmt::nested::Debug<|> for Foo { 377impl std::fmt::nested::Debug<|> for Foo {
310} 378}
311", 379",
312 " 380 r"
313use std::fmt::{Debug, nested::{Display, Debug}}; 381use std::fmt::{Debug, nested::{Display, Debug}};
314 382
315impl Debug for Foo { 383impl Debug for Foo {
@@ -322,13 +390,13 @@ impl Debug for Foo {
322 fn test_replace_split_common_target_longer() { 390 fn test_replace_split_common_target_longer() {
323 check_assist( 391 check_assist(
324 replace_qualified_name_with_use, 392 replace_qualified_name_with_use,
325 " 393 r"
326use std::fmt::Debug; 394use std::fmt::Debug;
327 395
328impl std::fmt::nested::Display<|> for Foo { 396impl std::fmt::nested::Display<|> for Foo {
329} 397}
330", 398",
331 " 399 r"
332use std::fmt::{nested::Display, Debug}; 400use std::fmt::{nested::Display, Debug};
333 401
334impl Display for Foo { 402impl Display for Foo {
@@ -341,13 +409,13 @@ impl Display for Foo {
341 fn test_replace_split_common_use_longer() { 409 fn test_replace_split_common_use_longer() {
342 check_assist( 410 check_assist(
343 replace_qualified_name_with_use, 411 replace_qualified_name_with_use,
344 " 412 r"
345use std::fmt::nested::Debug; 413use std::fmt::nested::Debug;
346 414
347impl std::fmt::Display<|> for Foo { 415impl std::fmt::Display<|> for Foo {
348} 416}
349", 417",
350 " 418 r"
351use std::fmt::{Display, nested::Debug}; 419use std::fmt::{Display, nested::Debug};
352 420
353impl Display for Foo { 421impl Display for Foo {
@@ -360,7 +428,7 @@ impl Display for Foo {
360 fn test_replace_use_nested_import() { 428 fn test_replace_use_nested_import() {
361 check_assist( 429 check_assist(
362 replace_qualified_name_with_use, 430 replace_qualified_name_with_use,
363 " 431 r"
364use crate::{ 432use crate::{
365 ty::{Substs, Ty}, 433 ty::{Substs, Ty},
366 AssocItem, 434 AssocItem,
@@ -368,7 +436,7 @@ use crate::{
368 436
369fn foo() { crate::ty::lower<|>::trait_env() } 437fn foo() { crate::ty::lower<|>::trait_env() }
370", 438",
371 " 439 r"
372use crate::{ 440use crate::{
373 ty::{Substs, Ty, lower}, 441 ty::{Substs, Ty, lower},
374 AssocItem, 442 AssocItem,
@@ -383,13 +451,13 @@ fn foo() { lower::trait_env() }
383 fn test_replace_alias() { 451 fn test_replace_alias() {
384 check_assist( 452 check_assist(
385 replace_qualified_name_with_use, 453 replace_qualified_name_with_use,
386 " 454 r"
387use std::fmt as foo; 455use std::fmt as foo;
388 456
389impl foo::Debug<|> for Foo { 457impl foo::Debug<|> for Foo {
390} 458}
391", 459",
392 " 460 r"
393use std::fmt as foo; 461use std::fmt as foo;
394 462
395impl Debug for Foo { 463impl Debug for Foo {
@@ -402,7 +470,7 @@ impl Debug for Foo {
402 fn test_replace_not_applicable_one_segment() { 470 fn test_replace_not_applicable_one_segment() {
403 check_assist_not_applicable( 471 check_assist_not_applicable(
404 replace_qualified_name_with_use, 472 replace_qualified_name_with_use,
405 " 473 r"
406impl foo<|> for Foo { 474impl foo<|> for Foo {
407} 475}
408", 476",
@@ -413,7 +481,7 @@ impl foo<|> for Foo {
413 fn test_replace_not_applicable_in_use() { 481 fn test_replace_not_applicable_in_use() {
414 check_assist_not_applicable( 482 check_assist_not_applicable(
415 replace_qualified_name_with_use, 483 replace_qualified_name_with_use,
416 " 484 r"
417use std::fmt<|>; 485use std::fmt<|>;
418", 486",
419 ); 487 );
@@ -423,14 +491,14 @@ use std::fmt<|>;
423 fn test_replace_add_use_no_anchor_in_mod_mod() { 491 fn test_replace_add_use_no_anchor_in_mod_mod() {
424 check_assist( 492 check_assist(
425 replace_qualified_name_with_use, 493 replace_qualified_name_with_use,
426 " 494 r"
427mod foo { 495mod foo {
428 mod bar { 496 mod bar {
429 std::fmt::Debug<|> 497 std::fmt::Debug<|>
430 } 498 }
431} 499}
432 ", 500 ",
433 " 501 r"
434mod foo { 502mod foo {
435 mod bar { 503 mod bar {
436 use std::fmt::Debug; 504 use std::fmt::Debug;
@@ -446,14 +514,14 @@ mod foo {
446 fn inserts_imports_after_inner_attributes() { 514 fn inserts_imports_after_inner_attributes() {
447 check_assist( 515 check_assist(
448 replace_qualified_name_with_use, 516 replace_qualified_name_with_use,
449 " 517 r"
450#![allow(dead_code)] 518#![allow(dead_code)]
451 519
452fn main() { 520fn main() {
453 std::fmt::Debug<|> 521 std::fmt::Debug<|>
454} 522}
455 ", 523 ",
456 " 524 r"
457#![allow(dead_code)] 525#![allow(dead_code)]
458use std::fmt::Debug; 526use std::fmt::Debug;
459 527
@@ -463,4 +531,116 @@ fn main() {
463 ", 531 ",
464 ); 532 );
465 } 533 }
534
535 #[test]
536 fn replaces_all_affected_paths() {
537 check_assist(
538 replace_qualified_name_with_use,
539 r"
540fn main() {
541 std::fmt::Debug<|>;
542 let x: std::fmt::Debug = std::fmt::Debug;
543}
544 ",
545 r"
546use std::fmt::Debug;
547
548fn main() {
549 Debug;
550 let x: Debug = Debug;
551}
552 ",
553 );
554 }
555
556 #[test]
557 fn replaces_all_affected_paths_mod() {
558 check_assist(
559 replace_qualified_name_with_use,
560 r"
561mod m {
562 fn f() {
563 std::fmt::Debug<|>;
564 let x: std::fmt::Debug = std::fmt::Debug;
565 }
566 fn g() {
567 std::fmt::Debug;
568 }
569}
570
571fn f() {
572 std::fmt::Debug;
573}
574 ",
575 r"
576mod m {
577 use std::fmt::Debug;
578
579 fn f() {
580 Debug;
581 let x: Debug = Debug;
582 }
583 fn g() {
584 Debug;
585 }
586}
587
588fn f() {
589 std::fmt::Debug;
590}
591 ",
592 );
593 }
594
595 #[test]
596 fn does_not_replace_in_submodules() {
597 check_assist(
598 replace_qualified_name_with_use,
599 r"
600fn main() {
601 std::fmt::Debug<|>;
602}
603
604mod sub {
605 fn f() {
606 std::fmt::Debug;
607 }
608}
609 ",
610 r"
611use std::fmt::Debug;
612
613fn main() {
614 Debug;
615}
616
617mod sub {
618 fn f() {
619 std::fmt::Debug;
620 }
621}
622 ",
623 );
624 }
625
626 #[test]
627 fn does_not_replace_in_use() {
628 check_assist(
629 replace_qualified_name_with_use,
630 r"
631use std::fmt::Display;
632
633fn main() {
634 std::fmt<|>;
635}
636 ",
637 r"
638use std::fmt::{self, Display};
639
640fn main() {
641 fmt;
642}
643 ",
644 );
645 }
466} 646}
diff --git a/crates/ra_assists/src/utils.rs b/crates/ra_assists/src/utils.rs
index 0038a9764..c1ff0de7b 100644
--- a/crates/ra_assists/src/utils.rs
+++ b/crates/ra_assists/src/utils.rs
@@ -13,7 +13,7 @@ use rustc_hash::FxHashSet;
13 13
14use crate::assist_config::SnippetCap; 14use crate::assist_config::SnippetCap;
15 15
16pub(crate) use insert_use::insert_use_statement; 16pub(crate) use insert_use::{find_insert_use_container, insert_use_statement};
17 17
18#[derive(Clone, Copy, Debug)] 18#[derive(Clone, Copy, Debug)]
19pub(crate) enum Cursor<'a> { 19pub(crate) enum Cursor<'a> {
diff --git a/crates/ra_assists/src/utils/insert_use.rs b/crates/ra_assists/src/utils/insert_use.rs
index 0ee43482f..8c4f33e59 100644
--- a/crates/ra_assists/src/utils/insert_use.rs
+++ b/crates/ra_assists/src/utils/insert_use.rs
@@ -12,6 +12,20 @@ use ra_syntax::{
12use ra_text_edit::TextEditBuilder; 12use ra_text_edit::TextEditBuilder;
13 13
14use crate::assist_context::AssistContext; 14use crate::assist_context::AssistContext;
15use either::Either;
16
17/// Determines the containing syntax node in which to insert a `use` statement affecting `position`.
18pub(crate) fn find_insert_use_container(
19 position: &SyntaxNode,
20 ctx: &AssistContext,
21) -> Option<Either<ast::ItemList, ast::SourceFile>> {
22 ctx.sema.ancestors_with_macros(position.clone()).find_map(|n| {
23 if let Some(module) = ast::Module::cast(n.clone()) {
24 return module.item_list().map(|it| Either::Left(it));
25 }
26 Some(Either::Right(ast::SourceFile::cast(n)?))
27 })
28}
15 29
16/// Creates and inserts a use statement for the given path to import. 30/// Creates and inserts a use statement for the given path to import.
17/// The use statement is inserted in the scope most appropriate to the 31/// The use statement is inserted in the scope most appropriate to the
@@ -24,15 +38,11 @@ pub(crate) fn insert_use_statement(
24 builder: &mut TextEditBuilder, 38 builder: &mut TextEditBuilder,
25) { 39) {
26 let target = path_to_import.to_string().split("::").map(SmolStr::new).collect::<Vec<_>>(); 40 let target = path_to_import.to_string().split("::").map(SmolStr::new).collect::<Vec<_>>();
27 let container = ctx.sema.ancestors_with_macros(position.clone()).find_map(|n| { 41 let container = find_insert_use_container(position, ctx);
28 if let Some(module) = ast::Module::cast(n.clone()) {
29 return module.item_list().map(|it| it.syntax().clone());
30 }
31 ast::SourceFile::cast(n).map(|it| it.syntax().clone())
32 });
33 42
34 if let Some(container) = container { 43 if let Some(container) = container {
35 let action = best_action_for_target(container, position.clone(), &target); 44 let syntax = container.either(|l| l.syntax().clone(), |r| r.syntax().clone());
45 let action = best_action_for_target(syntax, position.clone(), &target);
36 make_assist(&action, &target, builder); 46 make_assist(&action, &target, builder);
37 } 47 }
38} 48}
diff --git a/crates/ra_ide/src/lib.rs b/crates/ra_ide/src/lib.rs
index 28f686767..375da1f45 100644
--- a/crates/ra_ide/src/lib.rs
+++ b/crates/ra_ide/src/lib.rs
@@ -440,12 +440,14 @@ impl Analysis {
440 440
441 /// Computes syntax highlighting for the given file 441 /// Computes syntax highlighting for the given file
442 pub fn highlight(&self, file_id: FileId) -> Cancelable<Vec<HighlightedRange>> { 442 pub fn highlight(&self, file_id: FileId) -> Cancelable<Vec<HighlightedRange>> {
443 self.with_db(|db| syntax_highlighting::highlight(db, file_id, None)) 443 self.with_db(|db| syntax_highlighting::highlight(db, file_id, None, false))
444 } 444 }
445 445
446 /// Computes syntax highlighting for the given file range. 446 /// Computes syntax highlighting for the given file range.
447 pub fn highlight_range(&self, frange: FileRange) -> Cancelable<Vec<HighlightedRange>> { 447 pub fn highlight_range(&self, frange: FileRange) -> Cancelable<Vec<HighlightedRange>> {
448 self.with_db(|db| syntax_highlighting::highlight(db, frange.file_id, Some(frange.range))) 448 self.with_db(|db| {
449 syntax_highlighting::highlight(db, frange.file_id, Some(frange.range), false)
450 })
449 } 451 }
450 452
451 /// Computes syntax highlighting for the given file. 453 /// Computes syntax highlighting for the given file.
diff --git a/crates/ra_ide/src/prime_caches.rs b/crates/ra_ide/src/prime_caches.rs
index 90bf7d25f..c5ab5a1d8 100644
--- a/crates/ra_ide/src/prime_caches.rs
+++ b/crates/ra_ide/src/prime_caches.rs
@@ -7,6 +7,6 @@ use crate::{FileId, RootDatabase};
7 7
8pub(crate) fn prime_caches(db: &RootDatabase, files: Vec<FileId>) { 8pub(crate) fn prime_caches(db: &RootDatabase, files: Vec<FileId>) {
9 for file in files { 9 for file in files {
10 let _ = crate::syntax_highlighting::highlight(db, file, None); 10 let _ = crate::syntax_highlighting::highlight(db, file, None, false);
11 } 11 }
12} 12}
diff --git a/crates/ra_ide/src/snapshots/highlight_doctest.html b/crates/ra_ide/src/snapshots/highlight_doctest.html
index 0ae8c7efc..5228df267 100644
--- a/crates/ra_ide/src/snapshots/highlight_doctest.html
+++ b/crates/ra_ide/src/snapshots/highlight_doctest.html
@@ -25,22 +25,29 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
25.variable { color: #DCDCCC; } 25.variable { color: #DCDCCC; }
26.format_specifier { color: #CC696B; } 26.format_specifier { color: #CC696B; }
27.mutable { text-decoration: underline; } 27.mutable { text-decoration: underline; }
28.unresolved_reference { color: #FC5555; }
28 29
29.keyword { color: #F0DFAF; font-weight: bold; } 30.keyword { color: #F0DFAF; font-weight: bold; }
30.keyword.unsafe { color: #BC8383; font-weight: bold; } 31.keyword.unsafe { color: #BC8383; font-weight: bold; }
31.control { font-style: italic; } 32.control { font-style: italic; }
32</style> 33</style>
33<pre><code><span class="keyword">impl</span> <span class="unresolved_reference">Foo</span> { 34<pre><code><span class="keyword">struct</span> <span class="struct declaration">Foo</span> {
35 <span class="field declaration">bar</span>: <span class="builtin_type">bool</span>,
36}
37
38<span class="keyword">impl</span> <span class="struct">Foo</span> {
39 <span class="keyword">pub</span> <span class="keyword">const</span> <span class="constant declaration">bar</span>: <span class="builtin_type">bool</span> = <span class="bool_literal">true</span>;
40
34 <span class="comment">/// Constructs a new `Foo`.</span> 41 <span class="comment">/// Constructs a new `Foo`.</span>
35 <span class="comment">///</span> 42 <span class="comment">///</span>
36 <span class="comment">/// # Examples</span> 43 <span class="comment">/// # Examples</span>
37 <span class="comment">///</span> 44 <span class="comment">///</span>
38 <span class="comment">/// ```</span> 45 <span class="comment">/// ```</span>
39 <span class="comment">/// #</span> <span class="attribute">#![</span><span class="function attribute">allow</span><span class="attribute">(unused_mut)]</span> 46 <span class="comment">/// #</span> <span class="attribute">#![</span><span class="function attribute">allow</span><span class="attribute">(unused_mut)]</span>
40 <span class="comment">/// </span><span class="keyword">let</span> <span class="keyword">mut</span> <span class="variable declaration mutable">foo</span>: <span class="unresolved_reference">Foo</span> = <span class="unresolved_reference">Foo</span>::<span class="unresolved_reference">new</span>(); 47 <span class="comment">/// </span><span class="keyword">let</span> <span class="keyword">mut</span> <span class="variable declaration mutable">foo</span>: <span class="struct">Foo</span> = <span class="struct">Foo</span>::<span class="function">new</span>();
41 <span class="comment">/// ```</span> 48 <span class="comment">/// ```</span>
42 <span class="keyword">pub</span> <span class="keyword">const</span> <span class="keyword">fn</span> <span class="function declaration">new</span>() -&gt; <span class="unresolved_reference">Foo</span> { 49 <span class="keyword">pub</span> <span class="keyword">const</span> <span class="keyword">fn</span> <span class="function declaration">new</span>() -&gt; <span class="struct">Foo</span> {
43 <span class="unresolved_reference">Foo</span> { } 50 <span class="struct">Foo</span> { <span class="field">bar</span>: <span class="bool_literal">true</span> }
44 } 51 }
45 52
46 <span class="comment">/// `bar` method on `Foo`.</span> 53 <span class="comment">/// `bar` method on `Foo`.</span>
@@ -48,11 +55,15 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
48 <span class="comment">/// # Examples</span> 55 <span class="comment">/// # Examples</span>
49 <span class="comment">///</span> 56 <span class="comment">///</span>
50 <span class="comment">/// ```</span> 57 <span class="comment">/// ```</span>
51 <span class="comment">/// </span><span class="keyword">let</span> <span class="variable declaration">foo</span> = <span class="unresolved_reference">Foo</span>::<span class="unresolved_reference">new</span>(); 58 <span class="comment">/// </span><span class="keyword">use</span> <span class="module">x</span>::<span class="module">y</span>;
59 <span class="comment">///</span>
60 <span class="comment">/// </span><span class="keyword">let</span> <span class="variable declaration">foo</span> = <span class="struct">Foo</span>::<span class="function">new</span>();
52 <span class="comment">///</span> 61 <span class="comment">///</span>
53 <span class="comment">/// </span><span class="comment">// calls bar on foo</span> 62 <span class="comment">/// </span><span class="comment">// calls bar on foo</span>
54 <span class="comment">/// </span><span class="macro">assert!</span>(foo.bar()); 63 <span class="comment">/// </span><span class="macro">assert!</span>(foo.bar());
55 <span class="comment">///</span> 64 <span class="comment">///</span>
65 <span class="comment">/// </span><span class="keyword">let</span> <span class="variable declaration">bar</span> = <span class="variable">foo</span>.<span class="field">bar</span> || <span class="struct">Foo</span>::<span class="constant">bar</span>;
66 <span class="comment">///</span>
56 <span class="comment">/// </span><span class="comment">/* multi-line 67 <span class="comment">/// </span><span class="comment">/* multi-line
57 </span><span class="comment">/// </span><span class="comment"> comment */</span> 68 </span><span class="comment">/// </span><span class="comment"> comment */</span>
58 <span class="comment">///</span> 69 <span class="comment">///</span>
@@ -63,7 +74,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
63 <span class="comment">/// ```</span> 74 <span class="comment">/// ```</span>
64 <span class="comment">///</span> 75 <span class="comment">///</span>
65 <span class="comment">/// ```</span> 76 <span class="comment">/// ```</span>
66 <span class="comment">/// </span><span class="keyword">let</span> <span class="variable declaration">foobar</span> = <span class="unresolved_reference">Foo</span>::<span class="unresolved_reference">new</span>().<span class="unresolved_reference">bar</span>(); 77 <span class="comment">/// </span><span class="keyword">let</span> <span class="variable declaration">foobar</span> = <span class="struct">Foo</span>::<span class="function">new</span>().<span class="function">bar</span>();
67 <span class="comment">/// ```</span> 78 <span class="comment">/// ```</span>
68 <span class="keyword">pub</span> <span class="keyword">fn</span> <span class="function declaration">foo</span>(&<span class="self_keyword">self</span>) -&gt; <span class="builtin_type">bool</span> { 79 <span class="keyword">pub</span> <span class="keyword">fn</span> <span class="function declaration">foo</span>(&<span class="self_keyword">self</span>) -&gt; <span class="builtin_type">bool</span> {
69 <span class="bool_literal">true</span> 80 <span class="bool_literal">true</span>
diff --git a/crates/ra_ide/src/snapshots/highlight_injection.html b/crates/ra_ide/src/snapshots/highlight_injection.html
index dec06eb51..e1c9d3523 100644
--- a/crates/ra_ide/src/snapshots/highlight_injection.html
+++ b/crates/ra_ide/src/snapshots/highlight_injection.html
@@ -25,6 +25,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
25.variable { color: #DCDCCC; } 25.variable { color: #DCDCCC; }
26.format_specifier { color: #CC696B; } 26.format_specifier { color: #CC696B; }
27.mutable { text-decoration: underline; } 27.mutable { text-decoration: underline; }
28.unresolved_reference { color: #FC5555; }
28 29
29.keyword { color: #F0DFAF; font-weight: bold; } 30.keyword { color: #F0DFAF; font-weight: bold; }
30.keyword.unsafe { color: #BC8383; font-weight: bold; } 31.keyword.unsafe { color: #BC8383; font-weight: bold; }
diff --git a/crates/ra_ide/src/snapshots/highlight_strings.html b/crates/ra_ide/src/snapshots/highlight_strings.html
index 849eb3b73..666b48fd0 100644
--- a/crates/ra_ide/src/snapshots/highlight_strings.html
+++ b/crates/ra_ide/src/snapshots/highlight_strings.html
@@ -25,6 +25,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
25.variable { color: #DCDCCC; } 25.variable { color: #DCDCCC; }
26.format_specifier { color: #CC696B; } 26.format_specifier { color: #CC696B; }
27.mutable { text-decoration: underline; } 27.mutable { text-decoration: underline; }
28.unresolved_reference { color: #FC5555; }
28 29
29.keyword { color: #F0DFAF; font-weight: bold; } 30.keyword { color: #F0DFAF; font-weight: bold; }
30.keyword.unsafe { color: #BC8383; font-weight: bold; } 31.keyword.unsafe { color: #BC8383; font-weight: bold; }
diff --git a/crates/ra_ide/src/snapshots/highlight_unsafe.html b/crates/ra_ide/src/snapshots/highlight_unsafe.html
index bd24e6e38..e1540499b 100644
--- a/crates/ra_ide/src/snapshots/highlight_unsafe.html
+++ b/crates/ra_ide/src/snapshots/highlight_unsafe.html
@@ -25,6 +25,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
25.variable { color: #DCDCCC; } 25.variable { color: #DCDCCC; }
26.format_specifier { color: #CC696B; } 26.format_specifier { color: #CC696B; }
27.mutable { text-decoration: underline; } 27.mutable { text-decoration: underline; }
28.unresolved_reference { color: #FC5555; }
28 29
29.keyword { color: #F0DFAF; font-weight: bold; } 30.keyword { color: #F0DFAF; font-weight: bold; }
30.keyword.unsafe { color: #BC8383; font-weight: bold; } 31.keyword.unsafe { color: #BC8383; font-weight: bold; }
diff --git a/crates/ra_ide/src/snapshots/highlighting.html b/crates/ra_ide/src/snapshots/highlighting.html
index 33548d43c..52912dc93 100644
--- a/crates/ra_ide/src/snapshots/highlighting.html
+++ b/crates/ra_ide/src/snapshots/highlighting.html
@@ -25,6 +25,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
25.variable { color: #DCDCCC; } 25.variable { color: #DCDCCC; }
26.format_specifier { color: #CC696B; } 26.format_specifier { color: #CC696B; }
27.mutable { text-decoration: underline; } 27.mutable { text-decoration: underline; }
28.unresolved_reference { color: #FC5555; }
28 29
29.keyword { color: #F0DFAF; font-weight: bold; } 30.keyword { color: #F0DFAF; font-weight: bold; }
30.keyword.unsafe { color: #BC8383; font-weight: bold; } 31.keyword.unsafe { color: #BC8383; font-weight: bold; }
@@ -62,6 +63,12 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
62 } 63 }
63} 64}
64 65
66<span class="macro">macro_rules!</span> <span class="macro declaration">noop</span> {
67 ($expr:expr) =&gt; {
68 $expr
69 }
70}
71
65<span class="comment">// comment</span> 72<span class="comment">// comment</span>
66<span class="keyword">fn</span> <span class="function declaration">main</span>() { 73<span class="keyword">fn</span> <span class="function declaration">main</span>() {
67 <span class="macro">println!</span>(<span class="string_literal">"Hello, {}!"</span>, <span class="numeric_literal">92</span>); 74 <span class="macro">println!</span>(<span class="string_literal">"Hello, {}!"</span>, <span class="numeric_literal">92</span>);
@@ -80,6 +87,8 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
80 <span class="comment">// Do nothing</span> 87 <span class="comment">// Do nothing</span>
81 } 88 }
82 89
90 <span class="macro">noop!</span>(<span class="macro">noop</span><span class="macro">!</span>(<span class="numeric_literal">1</span>));
91
83 <span class="keyword">let</span> <span class="keyword">mut</span> <span class="variable declaration mutable">x</span> = <span class="numeric_literal">42</span>; 92 <span class="keyword">let</span> <span class="keyword">mut</span> <span class="variable declaration mutable">x</span> = <span class="numeric_literal">42</span>;
84 <span class="keyword">let</span> <span class="variable declaration mutable">y</span> = &<span class="keyword">mut</span> <span class="variable mutable">x</span>; 93 <span class="keyword">let</span> <span class="variable declaration mutable">y</span> = &<span class="keyword">mut</span> <span class="variable mutable">x</span>;
85 <span class="keyword">let</span> <span class="variable declaration">z</span> = &<span class="variable mutable">y</span>; 94 <span class="keyword">let</span> <span class="variable declaration">z</span> = &<span class="variable mutable">y</span>;
diff --git a/crates/ra_ide/src/snapshots/rainbow_highlighting.html b/crates/ra_ide/src/snapshots/rainbow_highlighting.html
index 1ab06182c..1d7f04882 100644
--- a/crates/ra_ide/src/snapshots/rainbow_highlighting.html
+++ b/crates/ra_ide/src/snapshots/rainbow_highlighting.html
@@ -25,6 +25,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
25.variable { color: #DCDCCC; } 25.variable { color: #DCDCCC; }
26.format_specifier { color: #CC696B; } 26.format_specifier { color: #CC696B; }
27.mutable { text-decoration: underline; } 27.mutable { text-decoration: underline; }
28.unresolved_reference { color: #FC5555; }
28 29
29.keyword { color: #F0DFAF; font-weight: bold; } 30.keyword { color: #F0DFAF; font-weight: bold; }
30.keyword.unsafe { color: #BC8383; font-weight: bold; } 31.keyword.unsafe { color: #BC8383; font-weight: bold; }
diff --git a/crates/ra_ide/src/syntax_highlighting.rs b/crates/ra_ide/src/syntax_highlighting.rs
index ab45c364a..5a4de450c 100644
--- a/crates/ra_ide/src/syntax_highlighting.rs
+++ b/crates/ra_ide/src/syntax_highlighting.rs
@@ -44,6 +44,7 @@ pub(crate) fn highlight(
44 db: &RootDatabase, 44 db: &RootDatabase,
45 file_id: FileId, 45 file_id: FileId,
46 range_to_highlight: Option<TextRange>, 46 range_to_highlight: Option<TextRange>,
47 syntactic_name_ref_highlighting: bool,
47) -> Vec<HighlightedRange> { 48) -> Vec<HighlightedRange> {
48 let _p = profile("highlight"); 49 let _p = profile("highlight");
49 let sema = Semantics::new(db); 50 let sema = Semantics::new(db);
@@ -104,6 +105,7 @@ pub(crate) fn highlight(
104 if let Some((highlight, binding_hash)) = highlight_element( 105 if let Some((highlight, binding_hash)) = highlight_element(
105 &sema, 106 &sema,
106 &mut bindings_shadow_count, 107 &mut bindings_shadow_count,
108 syntactic_name_ref_highlighting,
107 name.syntax().clone().into(), 109 name.syntax().clone().into(),
108 ) { 110 ) {
109 stack.add(HighlightedRange { 111 stack.add(HighlightedRange {
@@ -160,23 +162,25 @@ pub(crate) fn highlight(
160 // Check if macro takes a format string and remember it for highlighting later. 162 // Check if macro takes a format string and remember it for highlighting later.
161 // The macros that accept a format string expand to a compiler builtin macros 163 // The macros that accept a format string expand to a compiler builtin macros
162 // `format_args` and `format_args_nl`. 164 // `format_args` and `format_args_nl`.
163 if let Some(fmt_macro_call) = parent.parent().and_then(ast::MacroCall::cast) { 165 if let Some(name) = parent
164 if let Some(name) = 166 .parent()
165 fmt_macro_call.path().and_then(|p| p.segment()).and_then(|s| s.name_ref()) 167 .and_then(ast::MacroCall::cast)
166 { 168 .and_then(|mc| mc.path())
167 match name.text().as_str() { 169 .and_then(|p| p.segment())
168 "format_args" | "format_args_nl" => { 170 .and_then(|s| s.name_ref())
169 format_string = parent 171 {
170 .children_with_tokens() 172 match name.text().as_str() {
171 .filter(|t| t.kind() != WHITESPACE) 173 "format_args" | "format_args_nl" => {
172 .nth(1) 174 format_string = parent
173 .filter(|e| { 175 .children_with_tokens()
174 ast::String::can_cast(e.kind()) 176 .filter(|t| t.kind() != WHITESPACE)
175 || ast::RawString::can_cast(e.kind()) 177 .nth(1)
176 }) 178 .filter(|e| {
177 } 179 ast::String::can_cast(e.kind())
178 _ => {} 180 || ast::RawString::can_cast(e.kind())
181 })
179 } 182 }
183 _ => {}
180 } 184 }
181 } 185 }
182 186
@@ -198,9 +202,12 @@ pub(crate) fn highlight(
198 202
199 let is_format_string = format_string.as_ref() == Some(&element_to_highlight); 203 let is_format_string = format_string.as_ref() == Some(&element_to_highlight);
200 204
201 if let Some((highlight, binding_hash)) = 205 if let Some((highlight, binding_hash)) = highlight_element(
202 highlight_element(&sema, &mut bindings_shadow_count, element_to_highlight.clone()) 206 &sema,
203 { 207 &mut bindings_shadow_count,
208 syntactic_name_ref_highlighting,
209 element_to_highlight.clone(),
210 ) {
204 stack.add(HighlightedRange { range, highlight, binding_hash }); 211 stack.add(HighlightedRange { range, highlight, binding_hash });
205 if let Some(string) = 212 if let Some(string) =
206 element_to_highlight.as_token().cloned().and_then(ast::String::cast) 213 element_to_highlight.as_token().cloned().and_then(ast::String::cast)
@@ -408,6 +415,7 @@ fn macro_call_range(macro_call: &ast::MacroCall) -> Option<TextRange> {
408fn highlight_element( 415fn highlight_element(
409 sema: &Semantics<RootDatabase>, 416 sema: &Semantics<RootDatabase>,
410 bindings_shadow_count: &mut FxHashMap<Name, u32>, 417 bindings_shadow_count: &mut FxHashMap<Name, u32>,
418 syntactic_name_ref_highlighting: bool,
411 element: SyntaxElement, 419 element: SyntaxElement,
412) -> Option<(Highlight, Option<u64>)> { 420) -> Option<(Highlight, Option<u64>)> {
413 let db = sema.db; 421 let db = sema.db;
@@ -461,6 +469,7 @@ fn highlight_element(
461 } 469 }
462 NameRefClass::FieldShorthand { .. } => HighlightTag::Field.into(), 470 NameRefClass::FieldShorthand { .. } => HighlightTag::Field.into(),
463 }, 471 },
472 None if syntactic_name_ref_highlighting => highlight_name_ref_by_syntax(name_ref),
464 None => HighlightTag::UnresolvedReference.into(), 473 None => HighlightTag::UnresolvedReference.into(),
465 } 474 }
466 } 475 }
@@ -493,6 +502,9 @@ fn highlight_element(
493 h |= HighlightModifier::Unsafe; 502 h |= HighlightModifier::Unsafe;
494 h 503 h
495 } 504 }
505 T![!] if element.parent().and_then(ast::MacroCall::cast).is_some() => {
506 Highlight::new(HighlightTag::Macro)
507 }
496 508
497 k if k.is_keyword() => { 509 k if k.is_keyword() => {
498 let h = Highlight::new(HighlightTag::Keyword); 510 let h = Highlight::new(HighlightTag::Keyword);
@@ -609,3 +621,53 @@ fn highlight_name_by_syntax(name: ast::Name) -> Highlight {
609 621
610 tag.into() 622 tag.into()
611} 623}
624
625fn highlight_name_ref_by_syntax(name: ast::NameRef) -> Highlight {
626 let default = HighlightTag::UnresolvedReference;
627
628 let parent = match name.syntax().parent() {
629 Some(it) => it,
630 _ => return default.into(),
631 };
632
633 let tag = match parent.kind() {
634 METHOD_CALL_EXPR => HighlightTag::Function,
635 FIELD_EXPR => HighlightTag::Field,
636 PATH_SEGMENT => {
637 let path = match parent.parent().and_then(ast::Path::cast) {
638 Some(it) => it,
639 _ => return default.into(),
640 };
641 let expr = match path.syntax().parent().and_then(ast::PathExpr::cast) {
642 Some(it) => it,
643 _ => {
644 // within path, decide whether it is module or adt by checking for uppercase name
645 return if name.text().chars().next().unwrap_or_default().is_uppercase() {
646 HighlightTag::Struct
647 } else {
648 HighlightTag::Module
649 }
650 .into();
651 }
652 };
653 let parent = match expr.syntax().parent() {
654 Some(it) => it,
655 None => return default.into(),
656 };
657
658 match parent.kind() {
659 CALL_EXPR => HighlightTag::Function,
660 _ => {
661 if name.text().chars().next().unwrap_or_default().is_uppercase() {
662 HighlightTag::Struct
663 } else {
664 HighlightTag::Constant
665 }
666 }
667 }
668 }
669 _ => default,
670 };
671
672 tag.into()
673}
diff --git a/crates/ra_ide/src/syntax_highlighting/html.rs b/crates/ra_ide/src/syntax_highlighting/html.rs
index 5bada6252..853b4a20f 100644
--- a/crates/ra_ide/src/syntax_highlighting/html.rs
+++ b/crates/ra_ide/src/syntax_highlighting/html.rs
@@ -19,7 +19,7 @@ pub(crate) fn highlight_as_html(db: &RootDatabase, file_id: FileId, rainbow: boo
19 ) 19 )
20 } 20 }
21 21
22 let ranges = highlight(db, file_id, None); 22 let ranges = highlight(db, file_id, None, false);
23 let text = parse.tree().syntax().to_string(); 23 let text = parse.tree().syntax().to_string();
24 let mut prev_pos = TextSize::from(0); 24 let mut prev_pos = TextSize::from(0);
25 let mut buf = String::new(); 25 let mut buf = String::new();
@@ -84,6 +84,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
84.variable { color: #DCDCCC; } 84.variable { color: #DCDCCC; }
85.format_specifier { color: #CC696B; } 85.format_specifier { color: #CC696B; }
86.mutable { text-decoration: underline; } 86.mutable { text-decoration: underline; }
87.unresolved_reference { color: #FC5555; }
87 88
88.keyword { color: #F0DFAF; font-weight: bold; } 89.keyword { color: #F0DFAF; font-weight: bold; }
89.keyword.unsafe { color: #BC8383; font-weight: bold; } 90.keyword.unsafe { color: #BC8383; font-weight: bold; }
diff --git a/crates/ra_ide/src/syntax_highlighting/injection.rs b/crates/ra_ide/src/syntax_highlighting/injection.rs
index 3575a0fc6..a02ffe59e 100644
--- a/crates/ra_ide/src/syntax_highlighting/injection.rs
+++ b/crates/ra_ide/src/syntax_highlighting/injection.rs
@@ -137,7 +137,7 @@ pub(super) fn highlight_doc_comment(
137 let (analysis, tmp_file_id) = Analysis::from_single_file(text); 137 let (analysis, tmp_file_id) = Analysis::from_single_file(text);
138 138
139 stack.push(); 139 stack.push();
140 for mut h in analysis.highlight(tmp_file_id).unwrap() { 140 for mut h in analysis.with_db(|db| super::highlight(db, tmp_file_id, None, true)).unwrap() {
141 // Determine start offset and end offset in case of multi-line ranges 141 // Determine start offset and end offset in case of multi-line ranges
142 let mut start_offset = None; 142 let mut start_offset = None;
143 let mut end_offset = None; 143 let mut end_offset = None;
diff --git a/crates/ra_ide/src/syntax_highlighting/tests.rs b/crates/ra_ide/src/syntax_highlighting/tests.rs
index 949bf59a0..062b3ff4a 100644
--- a/crates/ra_ide/src/syntax_highlighting/tests.rs
+++ b/crates/ra_ide/src/syntax_highlighting/tests.rs
@@ -43,6 +43,12 @@ def_fn! {
43 } 43 }
44} 44}
45 45
46macro_rules! noop {
47 ($expr:expr) => {
48 $expr
49 }
50}
51
46// comment 52// comment
47fn main() { 53fn main() {
48 println!("Hello, {}!", 92); 54 println!("Hello, {}!", 92);
@@ -61,6 +67,8 @@ fn main() {
61 // Do nothing 67 // Do nothing
62 } 68 }
63 69
70 noop!(noop!(1));
71
64 let mut x = 42; 72 let mut x = 42;
65 let y = &mut x; 73 let y = &mut x;
66 let z = &y; 74 let z = &y;
@@ -279,7 +287,13 @@ fn main() {
279fn test_highlight_doctest() { 287fn test_highlight_doctest() {
280 check_highlighting( 288 check_highlighting(
281 r#" 289 r#"
290struct Foo {
291 bar: bool,
292}
293
282impl Foo { 294impl Foo {
295 pub const bar: bool = true;
296
283 /// Constructs a new `Foo`. 297 /// Constructs a new `Foo`.
284 /// 298 ///
285 /// # Examples 299 /// # Examples
@@ -289,7 +303,7 @@ impl Foo {
289 /// let mut foo: Foo = Foo::new(); 303 /// let mut foo: Foo = Foo::new();
290 /// ``` 304 /// ```
291 pub const fn new() -> Foo { 305 pub const fn new() -> Foo {
292 Foo { } 306 Foo { bar: true }
293 } 307 }
294 308
295 /// `bar` method on `Foo`. 309 /// `bar` method on `Foo`.
@@ -297,11 +311,15 @@ impl Foo {
297 /// # Examples 311 /// # Examples
298 /// 312 ///
299 /// ``` 313 /// ```
314 /// use x::y;
315 ///
300 /// let foo = Foo::new(); 316 /// let foo = Foo::new();
301 /// 317 ///
302 /// // calls bar on foo 318 /// // calls bar on foo
303 /// assert!(foo.bar()); 319 /// assert!(foo.bar());
304 /// 320 ///
321 /// let bar = foo.bar || Foo::bar;
322 ///
305 /// /* multi-line 323 /// /* multi-line
306 /// comment */ 324 /// comment */
307 /// 325 ///
@@ -322,7 +340,7 @@ impl Foo {
322 .trim(), 340 .trim(),
323 "crates/ra_ide/src/snapshots/highlight_doctest.html", 341 "crates/ra_ide/src/snapshots/highlight_doctest.html",
324 false, 342 false,
325 ) 343 );
326} 344}
327 345
328/// Highlights the code given by the `ra_fixture` argument, renders the 346/// Highlights the code given by the `ra_fixture` argument, renders the
diff --git a/crates/ra_project_model/src/lib.rs b/crates/ra_project_model/src/lib.rs
index cb0e27dce..9541362f5 100644
--- a/crates/ra_project_model/src/lib.rs
+++ b/crates/ra_project_model/src/lib.rs
@@ -29,13 +29,7 @@ pub enum ProjectWorkspace {
29 /// Project workspace was discovered by running `cargo metadata` and `rustc --print sysroot`. 29 /// Project workspace was discovered by running `cargo metadata` and `rustc --print sysroot`.
30 Cargo { cargo: CargoWorkspace, sysroot: Sysroot }, 30 Cargo { cargo: CargoWorkspace, sysroot: Sysroot },
31 /// Project workspace was manually specified using a `rust-project.json` file. 31 /// Project workspace was manually specified using a `rust-project.json` file.
32 Json { project: JsonProject }, 32 Json { project: JsonProject, project_location: PathBuf },
33}
34
35impl From<JsonProject> for ProjectWorkspace {
36 fn from(project: JsonProject) -> ProjectWorkspace {
37 ProjectWorkspace::Json { project }
38 }
39} 33}
40 34
41/// `PackageRoot` describes a package root folder. 35/// `PackageRoot` describes a package root folder.
@@ -164,10 +158,15 @@ impl ProjectWorkspace {
164 format!("Failed to open json file {}", project_json.display()) 158 format!("Failed to open json file {}", project_json.display())
165 })?; 159 })?;
166 let reader = BufReader::new(file); 160 let reader = BufReader::new(file);
161 let project_location = match project_json.parent() {
162 Some(parent) => PathBuf::from(parent),
163 None => PathBuf::new(),
164 };
167 ProjectWorkspace::Json { 165 ProjectWorkspace::Json {
168 project: from_reader(reader).with_context(|| { 166 project: from_reader(reader).with_context(|| {
169 format!("Failed to deserialize json file {}", project_json.display()) 167 format!("Failed to deserialize json file {}", project_json.display())
170 })?, 168 })?,
169 project_location: project_location,
171 } 170 }
172 } 171 }
173 ProjectManifest::CargoToml(cargo_toml) => { 172 ProjectManifest::CargoToml(cargo_toml) => {
@@ -200,9 +199,11 @@ impl ProjectWorkspace {
200 /// the root is a member of the current workspace 199 /// the root is a member of the current workspace
201 pub fn to_roots(&self) -> Vec<PackageRoot> { 200 pub fn to_roots(&self) -> Vec<PackageRoot> {
202 match self { 201 match self {
203 ProjectWorkspace::Json { project } => { 202 ProjectWorkspace::Json { project, project_location } => project
204 project.roots.iter().map(|r| PackageRoot::new_member(r.path.clone())).collect() 203 .roots
205 } 204 .iter()
205 .map(|r| PackageRoot::new_member(project_location.join(&r.path)))
206 .collect(),
206 ProjectWorkspace::Cargo { cargo, sysroot } => cargo 207 ProjectWorkspace::Cargo { cargo, sysroot } => cargo
207 .packages() 208 .packages()
208 .map(|pkg| PackageRoot { 209 .map(|pkg| PackageRoot {
@@ -219,7 +220,7 @@ impl ProjectWorkspace {
219 220
220 pub fn proc_macro_dylib_paths(&self) -> Vec<PathBuf> { 221 pub fn proc_macro_dylib_paths(&self) -> Vec<PathBuf> {
221 match self { 222 match self {
222 ProjectWorkspace::Json { project } => project 223 ProjectWorkspace::Json { project, .. } => project
223 .crates 224 .crates
224 .iter() 225 .iter()
225 .filter_map(|krate| krate.proc_macro_dylib_path.as_ref()) 226 .filter_map(|krate| krate.proc_macro_dylib_path.as_ref())
@@ -235,7 +236,7 @@ impl ProjectWorkspace {
235 236
236 pub fn n_packages(&self) -> usize { 237 pub fn n_packages(&self) -> usize {
237 match self { 238 match self {
238 ProjectWorkspace::Json { project } => project.crates.len(), 239 ProjectWorkspace::Json { project, .. } => project.crates.len(),
239 ProjectWorkspace::Cargo { cargo, sysroot } => { 240 ProjectWorkspace::Cargo { cargo, sysroot } => {
240 cargo.packages().len() + sysroot.crates().len() 241 cargo.packages().len() + sysroot.crates().len()
241 } 242 }
@@ -251,13 +252,14 @@ impl ProjectWorkspace {
251 ) -> CrateGraph { 252 ) -> CrateGraph {
252 let mut crate_graph = CrateGraph::default(); 253 let mut crate_graph = CrateGraph::default();
253 match self { 254 match self {
254 ProjectWorkspace::Json { project } => { 255 ProjectWorkspace::Json { project, project_location } => {
255 let crates: FxHashMap<_, _> = project 256 let crates: FxHashMap<_, _> = project
256 .crates 257 .crates
257 .iter() 258 .iter()
258 .enumerate() 259 .enumerate()
259 .filter_map(|(seq_index, krate)| { 260 .filter_map(|(seq_index, krate)| {
260 let file_id = load(&krate.root_module)?; 261 let file_path = project_location.join(&krate.root_module);
262 let file_id = load(&file_path)?;
261 let edition = match krate.edition { 263 let edition = match krate.edition {
262 json_project::Edition::Edition2015 => Edition::Edition2015, 264 json_project::Edition::Edition2015 => Edition::Edition2015,
263 json_project::Edition::Edition2018 => Edition::Edition2018, 265 json_project::Edition::Edition2018 => Edition::Edition2018,
@@ -540,7 +542,7 @@ impl ProjectWorkspace {
540 ProjectWorkspace::Cargo { cargo, .. } => { 542 ProjectWorkspace::Cargo { cargo, .. } => {
541 Some(cargo.workspace_root()).filter(|root| path.starts_with(root)) 543 Some(cargo.workspace_root()).filter(|root| path.starts_with(root))
542 } 544 }
543 ProjectWorkspace::Json { project: JsonProject { roots, .. } } => roots 545 ProjectWorkspace::Json { project: JsonProject { roots, .. }, .. } => roots
544 .iter() 546 .iter()
545 .find(|root| path.starts_with(&root.path)) 547 .find(|root| path.starts_with(&root.path))
546 .map(|root| root.path.as_ref()), 548 .map(|root| root.path.as_ref()),
diff --git a/crates/ra_syntax/src/algo.rs b/crates/ra_syntax/src/algo.rs
index 664894d1f..f7a885eb3 100644
--- a/crates/ra_syntax/src/algo.rs
+++ b/crates/ra_syntax/src/algo.rs
@@ -290,6 +290,11 @@ impl<'a> SyntaxRewriter<'a> {
290 N::cast(self.rewrite(node.syntax())).unwrap() 290 N::cast(self.rewrite(node.syntax())).unwrap()
291 } 291 }
292 292
293 /// Returns a node that encompasses all replacements to be done by this rewriter.
294 ///
295 /// Passing the returned node to `rewrite` will apply all replacements queued up in `self`.
296 ///
297 /// Returns `None` when there are no replacements.
293 pub fn rewrite_root(&self) -> Option<SyntaxNode> { 298 pub fn rewrite_root(&self) -> Option<SyntaxNode> {
294 assert!(self.f.is_none()); 299 assert!(self.f.is_none());
295 self.replacements 300 self.replacements
@@ -298,6 +303,9 @@ impl<'a> SyntaxRewriter<'a> {
298 SyntaxElement::Node(it) => it.clone(), 303 SyntaxElement::Node(it) => it.clone(),
299 SyntaxElement::Token(it) => it.parent(), 304 SyntaxElement::Token(it) => it.parent(),
300 }) 305 })
306 // If we only have one replacement, we must return its parent node, since `rewrite` does
307 // not replace the node passed to it.
308 .map(|it| it.parent().unwrap_or(it))
301 .fold1(|a, b| least_common_ancestor(&a, &b).unwrap()) 309 .fold1(|a, b| least_common_ancestor(&a, &b).unwrap())
302 } 310 }
303 311
diff --git a/crates/ra_syntax/src/lib.rs b/crates/ra_syntax/src/lib.rs
index 61e686da5..a33a35cc1 100644
--- a/crates/ra_syntax/src/lib.rs
+++ b/crates/ra_syntax/src/lib.rs
@@ -51,7 +51,8 @@ pub use crate::{
51 ptr::{AstPtr, SyntaxNodePtr}, 51 ptr::{AstPtr, SyntaxNodePtr},
52 syntax_error::SyntaxError, 52 syntax_error::SyntaxError,
53 syntax_node::{ 53 syntax_node::{
54 Direction, NodeOrToken, SyntaxElement, SyntaxNode, SyntaxToken, SyntaxTreeBuilder, 54 Direction, NodeOrToken, SyntaxElement, SyntaxElementChildren, SyntaxNode,
55 SyntaxNodeChildren, SyntaxToken, SyntaxTreeBuilder,
55 }, 56 },
56}; 57};
57pub use ra_parser::{SyntaxKind, T}; 58pub use ra_parser::{SyntaxKind, T};
diff --git a/crates/rust-analyzer/src/bin/main.rs b/crates/rust-analyzer/src/bin/main.rs
index 8d071ab1c..99e3f7173 100644
--- a/crates/rust-analyzer/src/bin/main.rs
+++ b/crates/rust-analyzer/src/bin/main.rs
@@ -108,11 +108,11 @@ fn run_server() -> Result<()> {
108 config.update(value); 108 config.update(value);
109 } 109 }
110 config.update_caps(&initialize_params.capabilities); 110 config.update_caps(&initialize_params.capabilities);
111 let cwd = std::env::current_dir()?;
112 config.root_path =
113 initialize_params.root_uri.and_then(|it| it.to_file_path().ok()).unwrap_or(cwd);
111 114
112 if config.linked_projects.is_empty() { 115 if config.linked_projects.is_empty() {
113 let cwd = std::env::current_dir()?;
114 let root =
115 initialize_params.root_uri.and_then(|it| it.to_file_path().ok()).unwrap_or(cwd);
116 let workspace_roots = initialize_params 116 let workspace_roots = initialize_params
117 .workspace_folders 117 .workspace_folders
118 .map(|workspaces| { 118 .map(|workspaces| {
@@ -122,7 +122,7 @@ fn run_server() -> Result<()> {
122 .collect::<Vec<_>>() 122 .collect::<Vec<_>>()
123 }) 123 })
124 .filter(|workspaces| !workspaces.is_empty()) 124 .filter(|workspaces| !workspaces.is_empty())
125 .unwrap_or_else(|| vec![root]); 125 .unwrap_or_else(|| vec![config.root_path.clone()]);
126 126
127 config.linked_projects = ProjectManifest::discover_all(&workspace_roots) 127 config.linked_projects = ProjectManifest::discover_all(&workspace_roots)
128 .into_iter() 128 .into_iter()
diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs
index 1253db836..0e7a937a0 100644
--- a/crates/rust-analyzer/src/config.rs
+++ b/crates/rust-analyzer/src/config.rs
@@ -38,12 +38,13 @@ pub struct Config {
38 38
39 pub with_sysroot: bool, 39 pub with_sysroot: bool,
40 pub linked_projects: Vec<LinkedProject>, 40 pub linked_projects: Vec<LinkedProject>,
41 pub root_path: PathBuf,
41} 42}
42 43
43#[derive(Debug, Clone)] 44#[derive(Debug, Clone)]
44pub enum LinkedProject { 45pub enum LinkedProject {
45 ProjectManifest(ProjectManifest), 46 ProjectManifest(ProjectManifest),
46 JsonProject(JsonProject), 47 InlineJsonProject(JsonProject),
47} 48}
48 49
49impl From<ProjectManifest> for LinkedProject { 50impl From<ProjectManifest> for LinkedProject {
@@ -54,7 +55,7 @@ impl From<ProjectManifest> for LinkedProject {
54 55
55impl From<JsonProject> for LinkedProject { 56impl From<JsonProject> for LinkedProject {
56 fn from(v: JsonProject) -> Self { 57 fn from(v: JsonProject) -> Self {
57 LinkedProject::JsonProject(v) 58 LinkedProject::InlineJsonProject(v)
58 } 59 }
59} 60}
60 61
@@ -167,6 +168,7 @@ impl Default for Config {
167 lens: LensConfig::default(), 168 lens: LensConfig::default(),
168 hover: HoverConfig::default(), 169 hover: HoverConfig::default(),
169 linked_projects: Vec::new(), 170 linked_projects: Vec::new(),
171 root_path: PathBuf::new(),
170 } 172 }
171 } 173 }
172} 174}
diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs
index 8ec571b70..cc9bb1726 100644
--- a/crates/rust-analyzer/src/main_loop.rs
+++ b/crates/rust-analyzer/src/main_loop.rs
@@ -121,7 +121,12 @@ pub fn main_loop(config: Config, connection: Connection) -> Result<()> {
121 }) 121 })
122 .ok() 122 .ok()
123 } 123 }
124 LinkedProject::JsonProject(it) => Some(it.clone().into()), 124 LinkedProject::InlineJsonProject(it) => {
125 Some(ra_project_model::ProjectWorkspace::Json {
126 project: it.clone(),
127 project_location: config.root_path.clone(),
128 })
129 }
125 }) 130 })
126 .collect::<Vec<_>>() 131 .collect::<Vec<_>>()
127 }; 132 };