aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
Diffstat (limited to 'crates')
-rw-r--r--crates/assists/src/handlers/generate_function.rs132
-rw-r--r--crates/assists/src/tests/generated.rs4
-rw-r--r--crates/base_db/src/input.rs28
-rw-r--r--crates/hir/src/code_model.rs6
-rw-r--r--crates/hir_def/src/body/lower.rs5
-rw-r--r--crates/ide/src/inlay_hints.rs81
-rw-r--r--crates/ide/src/lib.rs8
-rw-r--r--crates/ide/src/prime_caches.rs43
-rw-r--r--crates/ide/src/syntax_highlighting.rs118
-rw-r--r--crates/ide/src/syntax_highlighting/test_data/highlight_strings.html2
-rw-r--r--crates/ide/src/syntax_highlighting/test_data/highlighting.html6
-rw-r--r--crates/ide/src/syntax_highlighting/tests.rs4
-rw-r--r--crates/rust-analyzer/src/main_loop.rs42
-rw-r--r--crates/rust-analyzer/src/thread_pool.rs11
-rw-r--r--crates/syntax/src/ast/make.rs12
15 files changed, 383 insertions, 119 deletions
diff --git a/crates/assists/src/handlers/generate_function.rs b/crates/assists/src/handlers/generate_function.rs
index b38d64058..d23f4293b 100644
--- a/crates/assists/src/handlers/generate_function.rs
+++ b/crates/assists/src/handlers/generate_function.rs
@@ -36,8 +36,8 @@ use crate::{
36// bar("", baz()); 36// bar("", baz());
37// } 37// }
38// 38//
39// fn bar(arg: &str, baz: Baz) { 39// fn bar(arg: &str, baz: Baz) ${0:-> ()} {
40// ${0:todo!()} 40// todo!()
41// } 41// }
42// 42//
43// ``` 43// ```
@@ -80,9 +80,9 @@ pub(crate) fn generate_function(acc: &mut Assists, ctx: &AssistContext) -> Optio
80 80
81struct FunctionTemplate { 81struct FunctionTemplate {
82 insert_offset: TextSize, 82 insert_offset: TextSize,
83 placeholder_expr: ast::MacroCall,
84 leading_ws: String, 83 leading_ws: String,
85 fn_def: ast::Fn, 84 fn_def: ast::Fn,
85 ret_type: ast::RetType,
86 trailing_ws: String, 86 trailing_ws: String,
87 file: FileId, 87 file: FileId,
88} 88}
@@ -90,11 +90,9 @@ struct FunctionTemplate {
90impl FunctionTemplate { 90impl FunctionTemplate {
91 fn to_string(&self, cap: Option<SnippetCap>) -> String { 91 fn to_string(&self, cap: Option<SnippetCap>) -> String {
92 let f = match cap { 92 let f = match cap {
93 Some(cap) => render_snippet( 93 Some(cap) => {
94 cap, 94 render_snippet(cap, self.fn_def.syntax(), Cursor::Replace(self.ret_type.syntax()))
95 self.fn_def.syntax(), 95 }
96 Cursor::Replace(self.placeholder_expr.syntax()),
97 ),
98 None => self.fn_def.to_string(), 96 None => self.fn_def.to_string(),
99 }; 97 };
100 format!("{}{}{}", self.leading_ws, f, self.trailing_ws) 98 format!("{}{}{}", self.leading_ws, f, self.trailing_ws)
@@ -141,8 +139,14 @@ impl FunctionBuilder {
141 let placeholder_expr = make::expr_todo(); 139 let placeholder_expr = make::expr_todo();
142 let fn_body = make::block_expr(vec![], Some(placeholder_expr)); 140 let fn_body = make::block_expr(vec![], Some(placeholder_expr));
143 let visibility = if self.needs_pub { Some(make::visibility_pub_crate()) } else { None }; 141 let visibility = if self.needs_pub { Some(make::visibility_pub_crate()) } else { None };
144 let mut fn_def = 142 let mut fn_def = make::fn_(
145 make::fn_(visibility, self.fn_name, self.type_params, self.params, fn_body); 143 visibility,
144 self.fn_name,
145 self.type_params,
146 self.params,
147 fn_body,
148 Some(make::ret_type(make::ty("()"))),
149 );
146 let leading_ws; 150 let leading_ws;
147 let trailing_ws; 151 let trailing_ws;
148 152
@@ -163,12 +167,10 @@ impl FunctionBuilder {
163 } 167 }
164 }; 168 };
165 169
166 let placeholder_expr =
167 fn_def.syntax().descendants().find_map(ast::MacroCall::cast).unwrap();
168 FunctionTemplate { 170 FunctionTemplate {
169 insert_offset, 171 insert_offset,
170 placeholder_expr,
171 leading_ws, 172 leading_ws,
173 ret_type: fn_def.ret_type().unwrap(),
172 fn_def, 174 fn_def,
173 trailing_ws, 175 trailing_ws,
174 file: self.file, 176 file: self.file,
@@ -349,8 +351,8 @@ fn foo() {
349 bar(); 351 bar();
350} 352}
351 353
352fn bar() { 354fn bar() ${0:-> ()} {
353 ${0:todo!()} 355 todo!()
354} 356}
355", 357",
356 ) 358 )
@@ -376,8 +378,8 @@ impl Foo {
376 } 378 }
377} 379}
378 380
379fn bar() { 381fn bar() ${0:-> ()} {
380 ${0:todo!()} 382 todo!()
381} 383}
382", 384",
383 ) 385 )
@@ -400,8 +402,8 @@ fn foo1() {
400 bar(); 402 bar();
401} 403}
402 404
403fn bar() { 405fn bar() ${0:-> ()} {
404 ${0:todo!()} 406 todo!()
405} 407}
406 408
407fn foo2() {} 409fn foo2() {}
@@ -426,8 +428,8 @@ mod baz {
426 bar(); 428 bar();
427 } 429 }
428 430
429 fn bar() { 431 fn bar() ${0:-> ()} {
430 ${0:todo!()} 432 todo!()
431 } 433 }
432} 434}
433", 435",
@@ -452,8 +454,8 @@ fn foo() {
452 bar(baz()); 454 bar(baz());
453} 455}
454 456
455fn bar(baz: Baz) { 457fn bar(baz: Baz) ${0:-> ()} {
456 ${0:todo!()} 458 todo!()
457} 459}
458", 460",
459 ); 461 );
@@ -485,8 +487,8 @@ impl Baz {
485 } 487 }
486} 488}
487 489
488fn bar(baz: Baz) { 490fn bar(baz: Baz) ${0:-> ()} {
489 ${0:todo!()} 491 todo!()
490} 492}
491", 493",
492 ) 494 )
@@ -506,8 +508,8 @@ fn foo() {
506 bar("bar") 508 bar("bar")
507} 509}
508 510
509fn bar(arg: &str) { 511fn bar(arg: &str) ${0:-> ()} {
510 ${0:todo!()} 512 todo!()
511} 513}
512"#, 514"#,
513 ) 515 )
@@ -527,8 +529,8 @@ fn foo() {
527 bar('x') 529 bar('x')
528} 530}
529 531
530fn bar(arg: char) { 532fn bar(arg: char) ${0:-> ()} {
531 ${0:todo!()} 533 todo!()
532} 534}
533"#, 535"#,
534 ) 536 )
@@ -548,8 +550,8 @@ fn foo() {
548 bar(42) 550 bar(42)
549} 551}
550 552
551fn bar(arg: i32) { 553fn bar(arg: i32) ${0:-> ()} {
552 ${0:todo!()} 554 todo!()
553} 555}
554", 556",
555 ) 557 )
@@ -569,8 +571,8 @@ fn foo() {
569 bar(42 as u8) 571 bar(42 as u8)
570} 572}
571 573
572fn bar(arg: u8) { 574fn bar(arg: u8) ${0:-> ()} {
573 ${0:todo!()} 575 todo!()
574} 576}
575", 577",
576 ) 578 )
@@ -594,8 +596,8 @@ fn foo() {
594 bar(x as u8) 596 bar(x as u8)
595} 597}
596 598
597fn bar(x: u8) { 599fn bar(x: u8) ${0:-> ()} {
598 ${0:todo!()} 600 todo!()
599} 601}
600", 602",
601 ) 603 )
@@ -617,8 +619,8 @@ fn foo() {
617 bar(worble) 619 bar(worble)
618} 620}
619 621
620fn bar(worble: ()) { 622fn bar(worble: ()) ${0:-> ()} {
621 ${0:todo!()} 623 todo!()
622} 624}
623", 625",
624 ) 626 )
@@ -646,8 +648,8 @@ fn baz() {
646 bar(foo()) 648 bar(foo())
647} 649}
648 650
649fn bar(foo: impl Foo) { 651fn bar(foo: impl Foo) ${0:-> ()} {
650 ${0:todo!()} 652 todo!()
651} 653}
652", 654",
653 ) 655 )
@@ -673,8 +675,8 @@ fn foo() {
673 bar(&baz()) 675 bar(&baz())
674} 676}
675 677
676fn bar(baz: &Baz) { 678fn bar(baz: &Baz) ${0:-> ()} {
677 ${0:todo!()} 679 todo!()
678} 680}
679", 681",
680 ) 682 )
@@ -702,8 +704,8 @@ fn foo() {
702 bar(Baz::baz()) 704 bar(Baz::baz())
703} 705}
704 706
705fn bar(baz: Baz::Bof) { 707fn bar(baz: Baz::Bof) ${0:-> ()} {
706 ${0:todo!()} 708 todo!()
707} 709}
708", 710",
709 ) 711 )
@@ -725,8 +727,8 @@ fn foo<T>(t: T) {
725 bar(t) 727 bar(t)
726} 728}
727 729
728fn bar<T>(t: T) { 730fn bar<T>(t: T) ${0:-> ()} {
729 ${0:todo!()} 731 todo!()
730} 732}
731", 733",
732 ) 734 )
@@ -756,8 +758,8 @@ fn foo() {
756 bar(Baz::new); 758 bar(Baz::new);
757} 759}
758 760
759fn bar(arg: fn() -> Baz) { 761fn bar(arg: fn() -> Baz) ${0:-> ()} {
760 ${0:todo!()} 762 todo!()
761} 763}
762", 764",
763 ) 765 )
@@ -781,8 +783,8 @@ fn foo() {
781 bar(closure) 783 bar(closure)
782} 784}
783 785
784fn bar(closure: impl Fn(i64) -> i64) { 786fn bar(closure: impl Fn(i64) -> i64) ${0:-> ()} {
785 ${0:todo!()} 787 todo!()
786} 788}
787", 789",
788 ) 790 )
@@ -802,8 +804,8 @@ fn foo() {
802 bar(baz) 804 bar(baz)
803} 805}
804 806
805fn bar(baz: ()) { 807fn bar(baz: ()) ${0:-> ()} {
806 ${0:todo!()} 808 todo!()
807} 809}
808", 810",
809 ) 811 )
@@ -827,8 +829,8 @@ fn foo() {
827 bar(baz(), baz()) 829 bar(baz(), baz())
828} 830}
829 831
830fn bar(baz_1: Baz, baz_2: Baz) { 832fn bar(baz_1: Baz, baz_2: Baz) ${0:-> ()} {
831 ${0:todo!()} 833 todo!()
832} 834}
833", 835",
834 ) 836 )
@@ -852,8 +854,8 @@ fn foo() {
852 bar(baz(), baz(), "foo", "bar") 854 bar(baz(), baz(), "foo", "bar")
853} 855}
854 856
855fn bar(baz_1: Baz, baz_2: Baz, arg_1: &str, arg_2: &str) { 857fn bar(baz_1: Baz, baz_2: Baz, arg_1: &str, arg_2: &str) ${0:-> ()} {
856 ${0:todo!()} 858 todo!()
857} 859}
858"#, 860"#,
859 ) 861 )
@@ -872,8 +874,8 @@ fn foo() {
872", 874",
873 r" 875 r"
874mod bar { 876mod bar {
875 pub(crate) fn my_fn() { 877 pub(crate) fn my_fn() ${0:-> ()} {
876 ${0:todo!()} 878 todo!()
877 } 879 }
878} 880}
879 881
@@ -911,8 +913,8 @@ fn bar() {
911 baz(foo) 913 baz(foo)
912} 914}
913 915
914fn baz(foo: foo::Foo) { 916fn baz(foo: foo::Foo) ${0:-> ()} {
915 ${0:todo!()} 917 todo!()
916} 918}
917", 919",
918 ) 920 )
@@ -935,8 +937,8 @@ fn foo() {
935mod bar { 937mod bar {
936 fn something_else() {} 938 fn something_else() {}
937 939
938 pub(crate) fn my_fn() { 940 pub(crate) fn my_fn() ${0:-> ()} {
939 ${0:todo!()} 941 todo!()
940 } 942 }
941} 943}
942 944
@@ -963,8 +965,8 @@ fn foo() {
963 r" 965 r"
964mod bar { 966mod bar {
965 mod baz { 967 mod baz {
966 pub(crate) fn my_fn() { 968 pub(crate) fn my_fn() ${0:-> ()} {
967 ${0:todo!()} 969 todo!()
968 } 970 }
969 } 971 }
970} 972}
@@ -992,8 +994,8 @@ fn main() {
992 r" 994 r"
993 995
994 996
995pub(crate) fn bar() { 997pub(crate) fn bar() ${0:-> ()} {
996 ${0:todo!()} 998 todo!()
997}", 999}",
998 ) 1000 )
999 } 1001 }
diff --git a/crates/assists/src/tests/generated.rs b/crates/assists/src/tests/generated.rs
index 7f6e98a54..41f536574 100644
--- a/crates/assists/src/tests/generated.rs
+++ b/crates/assists/src/tests/generated.rs
@@ -454,8 +454,8 @@ fn foo() {
454 bar("", baz()); 454 bar("", baz());
455} 455}
456 456
457fn bar(arg: &str, baz: Baz) { 457fn bar(arg: &str, baz: Baz) ${0:-> ()} {
458 ${0:todo!()} 458 todo!()
459} 459}
460 460
461"#####, 461"#####,
diff --git a/crates/base_db/src/input.rs b/crates/base_db/src/input.rs
index c330314d4..215ac4b41 100644
--- a/crates/base_db/src/input.rs
+++ b/crates/base_db/src/input.rs
@@ -221,6 +221,34 @@ impl CrateGraph {
221 deps.into_iter() 221 deps.into_iter()
222 } 222 }
223 223
224 /// Returns all crates in the graph, sorted in topological order (ie. dependencies of a crate
225 /// come before the crate itself).
226 pub fn crates_in_topological_order(&self) -> Vec<CrateId> {
227 let mut res = Vec::new();
228 let mut visited = FxHashSet::default();
229
230 for krate in self.arena.keys().copied() {
231 go(self, &mut visited, &mut res, krate);
232 }
233
234 return res;
235
236 fn go(
237 graph: &CrateGraph,
238 visited: &mut FxHashSet<CrateId>,
239 res: &mut Vec<CrateId>,
240 source: CrateId,
241 ) {
242 if !visited.insert(source) {
243 return;
244 }
245 for dep in graph[source].dependencies.iter() {
246 go(graph, visited, res, dep.crate_id)
247 }
248 res.push(source)
249 }
250 }
251
224 // FIXME: this only finds one crate with the given root; we could have multiple 252 // FIXME: this only finds one crate with the given root; we could have multiple
225 pub fn crate_id_for_crate_root(&self, file_id: FileId) -> Option<CrateId> { 253 pub fn crate_id_for_crate_root(&self, file_id: FileId) -> Option<CrateId> {
226 let (&crate_id, _) = 254 let (&crate_id, _) =
diff --git a/crates/hir/src/code_model.rs b/crates/hir/src/code_model.rs
index fb85041fd..b65be4fe1 100644
--- a/crates/hir/src/code_model.rs
+++ b/crates/hir/src/code_model.rs
@@ -1411,7 +1411,7 @@ impl Type {
1411 r#trait: Trait, 1411 r#trait: Trait,
1412 args: &[Type], 1412 args: &[Type],
1413 alias: TypeAlias, 1413 alias: TypeAlias,
1414 ) -> Option<Ty> { 1414 ) -> Option<Type> {
1415 let subst = Substs::build_for_def(db, r#trait.id) 1415 let subst = Substs::build_for_def(db, r#trait.id)
1416 .push(self.ty.value.clone()) 1416 .push(self.ty.value.clone())
1417 .fill(args.iter().map(|t| t.ty.value.clone())) 1417 .fill(args.iter().map(|t| t.ty.value.clone()))
@@ -1432,6 +1432,10 @@ impl Type {
1432 Solution::Unique(SolutionVariables(subst)) => subst.value.first().cloned(), 1432 Solution::Unique(SolutionVariables(subst)) => subst.value.first().cloned(),
1433 Solution::Ambig(_) => None, 1433 Solution::Ambig(_) => None,
1434 } 1434 }
1435 .map(|ty| Type {
1436 krate: self.krate,
1437 ty: InEnvironment { value: ty, environment: Arc::clone(&self.ty.environment) },
1438 })
1435 } 1439 }
1436 1440
1437 pub fn is_copy(&self, db: &dyn HirDatabase) -> bool { 1441 pub fn is_copy(&self, db: &dyn HirDatabase) -> bool {
diff --git a/crates/hir_def/src/body/lower.rs b/crates/hir_def/src/body/lower.rs
index 2d91bb21f..01e72690a 100644
--- a/crates/hir_def/src/body/lower.rs
+++ b/crates/hir_def/src/body/lower.rs
@@ -107,7 +107,10 @@ impl ExprCollector<'_> {
107 let param_pat = self.alloc_pat( 107 let param_pat = self.alloc_pat(
108 Pat::Bind { 108 Pat::Bind {
109 name: name![self], 109 name: name![self],
110 mode: BindingAnnotation::Unannotated, 110 mode: BindingAnnotation::new(
111 self_param.mut_token().is_some() && self_param.amp_token().is_none(),
112 false,
113 ),
111 subpat: None, 114 subpat: None,
112 }, 115 },
113 Either::Right(ptr), 116 Either::Right(ptr),
diff --git a/crates/ide/src/inlay_hints.rs b/crates/ide/src/inlay_hints.rs
index 7d716577e..e2079bbcf 100644
--- a/crates/ide/src/inlay_hints.rs
+++ b/crates/ide/src/inlay_hints.rs
@@ -220,8 +220,8 @@ fn hint_iterator(
220 } 220 }
221 let iter_trait = FamousDefs(sema, krate).core_iter_Iterator()?; 221 let iter_trait = FamousDefs(sema, krate).core_iter_Iterator()?;
222 let iter_mod = FamousDefs(sema, krate).core_iter()?; 222 let iter_mod = FamousDefs(sema, krate).core_iter()?;
223 // assert this type comes from `core::iter` 223 // assert this struct comes from `core::iter`
224 iter_mod.visibility_of(db, &iter_trait.into()).filter(|&vis| vis == hir::Visibility::Public)?; 224 iter_mod.visibility_of(db, &strukt.into()).filter(|&vis| vis == hir::Visibility::Public)?;
225 if ty.impls_trait(db, iter_trait, &[]) { 225 if ty.impls_trait(db, iter_trait, &[]) {
226 let assoc_type_item = iter_trait.items(db).into_iter().find_map(|item| match item { 226 let assoc_type_item = iter_trait.items(db).into_iter().find_map(|item| match item {
227 hir::AssocItem::TypeAlias(alias) if alias.name(db) == known::Item => Some(alias), 227 hir::AssocItem::TypeAlias(alias) if alias.name(db) == known::Item => Some(alias),
@@ -231,12 +231,17 @@ fn hint_iterator(
231 const LABEL_START: &str = "impl Iterator<Item = "; 231 const LABEL_START: &str = "impl Iterator<Item = ";
232 const LABEL_END: &str = ">"; 232 const LABEL_END: &str = ">";
233 233
234 let ty_display = ty.display_truncated( 234 let ty_display = hint_iterator(sema, config, &ty)
235 db, 235 .map(|assoc_type_impl| assoc_type_impl.to_string())
236 config 236 .unwrap_or_else(|| {
237 .max_length 237 ty.display_truncated(
238 .map(|len| len.saturating_sub(LABEL_START.len() + LABEL_END.len())), 238 db,
239 ); 239 config
240 .max_length
241 .map(|len| len.saturating_sub(LABEL_START.len() + LABEL_END.len())),
242 )
243 .to_string()
244 });
240 return Some(format!("{}{}{}", LABEL_START, ty_display, LABEL_END).into()); 245 return Some(format!("{}{}{}", LABEL_START, ty_display, LABEL_END).into());
241 } 246 }
242 } 247 }
@@ -1002,18 +1007,6 @@ fn main() {
1002 1007
1003 println!("Unit expr"); 1008 println!("Unit expr");
1004} 1009}
1005
1006//- /alloc.rs crate:alloc deps:core
1007mod collections {
1008 struct Vec<T> {}
1009 impl<T> Vec<T> {
1010 fn new() -> Self { Vec {} }
1011 fn push(&mut self, t: T) { }
1012 }
1013 impl<T> IntoIterator for Vec<T> {
1014 type Item=T;
1015 }
1016}
1017"#, 1010"#,
1018 ); 1011 );
1019 } 1012 }
@@ -1043,17 +1036,6 @@ fn main() {
1043 //^ &str 1036 //^ &str
1044 } 1037 }
1045} 1038}
1046//- /alloc.rs crate:alloc deps:core
1047mod collections {
1048 struct Vec<T> {}
1049 impl<T> Vec<T> {
1050 fn new() -> Self { Vec {} }
1051 fn push(&mut self, t: T) { }
1052 }
1053 impl<T> IntoIterator for Vec<T> {
1054 type Item=T;
1055 }
1056}
1057"#, 1039"#,
1058 ); 1040 );
1059 } 1041 }
@@ -1183,4 +1165,41 @@ fn main() {
1183 "#]], 1165 "#]],
1184 ); 1166 );
1185 } 1167 }
1168
1169 #[test]
1170 fn shorten_iterators_in_associated_params() {
1171 check_with_config(
1172 InlayHintsConfig {
1173 parameter_hints: false,
1174 type_hints: true,
1175 chaining_hints: false,
1176 max_length: None,
1177 },
1178 r#"
1179use core::iter;
1180
1181pub struct SomeIter<T> {}
1182
1183impl<T> SomeIter<T> {
1184 pub fn new() -> Self { SomeIter {} }
1185 pub fn push(&mut self, t: T) {}
1186}
1187
1188impl<T> Iterator for SomeIter<T> {
1189 type Item = T;
1190 fn next(&mut self) -> Option<Self::Item> {
1191 None
1192 }
1193}
1194
1195fn main() {
1196 let mut some_iter = SomeIter::new();
1197 //^^^^^^^^^^^^^ SomeIter<Take<Repeat<i32>>>
1198 some_iter.push(iter::repeat(2).take(2));
1199 let iter_of_iters = some_iter.take(2);
1200 //^^^^^^^^^^^^^ impl Iterator<Item = impl Iterator<Item = i32>>
1201}
1202"#,
1203 );
1204 }
1186} 1205}
diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs
index 686cee3a1..aaf9b3b4b 100644
--- a/crates/ide/src/lib.rs
+++ b/crates/ide/src/lib.rs
@@ -77,6 +77,7 @@ pub use crate::{
77 hover::{HoverAction, HoverConfig, HoverGotoTypeData, HoverResult}, 77 hover::{HoverAction, HoverConfig, HoverGotoTypeData, HoverResult},
78 inlay_hints::{InlayHint, InlayHintsConfig, InlayKind}, 78 inlay_hints::{InlayHint, InlayHintsConfig, InlayKind},
79 markup::Markup, 79 markup::Markup,
80 prime_caches::PrimeCachesProgress,
80 references::{ 81 references::{
81 Declaration, Reference, ReferenceAccess, ReferenceKind, ReferenceSearchResult, RenameError, 82 Declaration, Reference, ReferenceAccess, ReferenceKind, ReferenceSearchResult, RenameError,
82 }, 83 },
@@ -223,8 +224,11 @@ impl Analysis {
223 self.with_db(|db| status::status(&*db, file_id)) 224 self.with_db(|db| status::status(&*db, file_id))
224 } 225 }
225 226
226 pub fn prime_caches(&self, files: Vec<FileId>) -> Cancelable<()> { 227 pub fn prime_caches<F>(&self, cb: F) -> Cancelable<()>
227 self.with_db(|db| prime_caches::prime_caches(db, files)) 228 where
229 F: Fn(PrimeCachesProgress) + Sync + std::panic::UnwindSafe,
230 {
231 self.with_db(move |db| prime_caches::prime_caches(db, &cb))
228 } 232 }
229 233
230 /// Gets the text of the source file. 234 /// Gets the text of the source file.
diff --git a/crates/ide/src/prime_caches.rs b/crates/ide/src/prime_caches.rs
index c5ab5a1d8..9687c2734 100644
--- a/crates/ide/src/prime_caches.rs
+++ b/crates/ide/src/prime_caches.rs
@@ -3,10 +3,45 @@
3//! request takes longer to compute. This modules implemented prepopulating of 3//! request takes longer to compute. This modules implemented prepopulating of
4//! various caches, it's not really advanced at the moment. 4//! various caches, it's not really advanced at the moment.
5 5
6use crate::{FileId, RootDatabase}; 6use base_db::SourceDatabase;
7use hir::db::DefDatabase;
7 8
8pub(crate) fn prime_caches(db: &RootDatabase, files: Vec<FileId>) { 9use crate::RootDatabase;
9 for file in files { 10
10 let _ = crate::syntax_highlighting::highlight(db, file, None, false); 11#[derive(Debug)]
12pub enum PrimeCachesProgress {
13 Started,
14 /// We started indexing a crate.
15 StartedOnCrate {
16 on_crate: String,
17 n_done: usize,
18 n_total: usize,
19 },
20 /// We finished indexing all crates.
21 Finished,
22}
23
24pub(crate) fn prime_caches(db: &RootDatabase, cb: &(dyn Fn(PrimeCachesProgress) + Sync)) {
25 let _p = profile::span("prime_caches");
26 let graph = db.crate_graph();
27 let topo = &graph.crates_in_topological_order();
28
29 cb(PrimeCachesProgress::Started);
30
31 // FIXME: This would be easy to parallelize, since it's in the ideal ordering for that.
32 // Unfortunately rayon prevents panics from propagation out of a `scope`, which breaks
33 // cancellation, so we cannot use rayon.
34 for (i, krate) in topo.iter().enumerate() {
35 let crate_name =
36 graph[*krate].declaration_name.as_ref().map(ToString::to_string).unwrap_or_default();
37
38 cb(PrimeCachesProgress::StartedOnCrate {
39 on_crate: crate_name,
40 n_done: i,
41 n_total: topo.len(),
42 });
43 db.crate_def_map(*krate);
11 } 44 }
45
46 cb(PrimeCachesProgress::Finished);
12} 47}
diff --git a/crates/ide/src/syntax_highlighting.rs b/crates/ide/src/syntax_highlighting.rs
index d9fc25d88..6aafd6fd5 100644
--- a/crates/ide/src/syntax_highlighting.rs
+++ b/crates/ide/src/syntax_highlighting.rs
@@ -68,7 +68,7 @@ pub(crate) fn highlight(
68 // When we leave a node, the we use it to flatten the highlighted ranges. 68 // When we leave a node, the we use it to flatten the highlighted ranges.
69 let mut stack = HighlightedRangeStack::new(); 69 let mut stack = HighlightedRangeStack::new();
70 70
71 let mut current_macro_call: Option<ast::MacroCall> = None; 71 let mut current_macro_call: Option<(ast::MacroCall, Option<MacroMatcherParseState>)> = None;
72 let mut format_string: Option<SyntaxElement> = None; 72 let mut format_string: Option<SyntaxElement> = None;
73 73
74 // Walk all nodes, keeping track of whether we are inside a macro or not. 74 // Walk all nodes, keeping track of whether we are inside a macro or not.
@@ -92,7 +92,6 @@ pub(crate) fn highlight(
92 // Track "inside macro" state 92 // Track "inside macro" state
93 match event.clone().map(|it| it.into_node().and_then(ast::MacroCall::cast)) { 93 match event.clone().map(|it| it.into_node().and_then(ast::MacroCall::cast)) {
94 WalkEvent::Enter(Some(mc)) => { 94 WalkEvent::Enter(Some(mc)) => {
95 current_macro_call = Some(mc.clone());
96 if let Some(range) = macro_call_range(&mc) { 95 if let Some(range) = macro_call_range(&mc) {
97 stack.add(HighlightedRange { 96 stack.add(HighlightedRange {
98 range, 97 range,
@@ -100,7 +99,9 @@ pub(crate) fn highlight(
100 binding_hash: None, 99 binding_hash: None,
101 }); 100 });
102 } 101 }
102 let mut is_macro_rules = None;
103 if let Some(name) = mc.is_macro_rules() { 103 if let Some(name) = mc.is_macro_rules() {
104 is_macro_rules = Some(MacroMatcherParseState::new());
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,
@@ -114,10 +115,11 @@ pub(crate) fn highlight(
114 }); 115 });
115 } 116 }
116 } 117 }
118 current_macro_call = Some((mc.clone(), is_macro_rules));
117 continue; 119 continue;
118 } 120 }
119 WalkEvent::Leave(Some(mc)) => { 121 WalkEvent::Leave(Some(mc)) => {
120 assert!(current_macro_call == Some(mc)); 122 assert!(current_macro_call.map(|it| it.0) == Some(mc));
121 current_macro_call = None; 123 current_macro_call = None;
122 format_string = None; 124 format_string = None;
123 } 125 }
@@ -146,6 +148,20 @@ pub(crate) fn highlight(
146 WalkEvent::Leave(_) => continue, 148 WalkEvent::Leave(_) => continue,
147 }; 149 };
148 150
151 // check if in matcher part of a macro_rules rule
152 if let Some((_, Some(ref mut state))) = current_macro_call {
153 if let Some(tok) = element.as_token() {
154 if matches!(
155 update_macro_rules_state(tok, state),
156 RuleState::Matcher | RuleState::Expander
157 ) {
158 if skip_metavariables(element.clone()) {
159 continue;
160 }
161 }
162 }
163 }
164
149 let range = element.text_range(); 165 let range = element.text_range();
150 166
151 let element_to_highlight = if current_macro_call.is_some() && element.kind() != COMMENT { 167 let element_to_highlight = if current_macro_call.is_some() && element.kind() != COMMENT {
@@ -918,3 +934,99 @@ fn highlight_name_ref_by_syntax(name: ast::NameRef, sema: &Semantics<RootDatabas
918 _ => default.into(), 934 _ => default.into(),
919 } 935 }
920} 936}
937
938struct MacroMatcherParseState {
939 /// Opening and corresponding closing bracket of the matcher or expander of the current rule
940 paren_ty: Option<(SyntaxKind, SyntaxKind)>,
941 paren_level: usize,
942 rule_state: RuleState,
943 /// Whether we are inside the outer `{` `}` macro block that holds the rules
944 in_invoc_body: bool,
945}
946
947impl MacroMatcherParseState {
948 fn new() -> Self {
949 MacroMatcherParseState {
950 paren_ty: None,
951 paren_level: 0,
952 in_invoc_body: false,
953 rule_state: RuleState::None,
954 }
955 }
956}
957
958#[derive(Copy, Clone, PartialEq)]
959enum RuleState {
960 Matcher,
961 Expander,
962 Between,
963 None,
964}
965
966impl RuleState {
967 fn transition(&mut self) {
968 *self = match self {
969 RuleState::Matcher => RuleState::Between,
970 RuleState::Expander => RuleState::None,
971 RuleState::Between => RuleState::Expander,
972 RuleState::None => RuleState::Matcher,
973 };
974 }
975}
976
977fn update_macro_rules_state(tok: &SyntaxToken, state: &mut MacroMatcherParseState) -> RuleState {
978 if !state.in_invoc_body {
979 if tok.kind() == T!['{'] {
980 state.in_invoc_body = true;
981 }
982 return state.rule_state;
983 }
984
985 match state.paren_ty {
986 Some((open, close)) => {
987 if tok.kind() == open {
988 state.paren_level += 1;
989 } else if tok.kind() == close {
990 state.paren_level -= 1;
991 if state.paren_level == 0 {
992 let res = state.rule_state;
993 state.rule_state.transition();
994 state.paren_ty = None;
995 return res;
996 }
997 }
998 }
999 None => {
1000 match tok.kind() {
1001 T!['('] => {
1002 state.paren_ty = Some((T!['('], T![')']));
1003 }
1004 T!['{'] => {
1005 state.paren_ty = Some((T!['{'], T!['}']));
1006 }
1007 T!['['] => {
1008 state.paren_ty = Some((T!['['], T![']']));
1009 }
1010 _ => (),
1011 }
1012 if state.paren_ty.is_some() {
1013 state.paren_level = 1;
1014 state.rule_state.transition();
1015 }
1016 }
1017 }
1018 state.rule_state
1019}
1020
1021fn skip_metavariables(element: SyntaxElement) -> bool {
1022 let tok = match element.as_token() {
1023 Some(tok) => tok,
1024 None => return false,
1025 };
1026 let is_fragment = || tok.prev_token().map(|tok| tok.kind()) == Some(T![$]);
1027 match tok.kind() {
1028 IDENT if is_fragment() => true,
1029 kind if kind.is_keyword() && is_fragment() => true,
1030 _ => false,
1031 }
1032}
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html b/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html
index 1b681b2c6..43f1b32fd 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html
@@ -37,7 +37,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
37</style> 37</style>
38<pre><code><span class="macro">macro_rules!</span> <span class="macro declaration">println</span> <span class="punctuation">{</span> 38<pre><code><span class="macro">macro_rules!</span> <span class="macro declaration">println</span> <span class="punctuation">{</span>
39 <span class="punctuation">(</span><span class="punctuation">$</span><span class="punctuation">(</span><span class="punctuation">$</span>arg<span class="punctuation">:</span>tt<span class="punctuation">)</span><span class="punctuation">*</span><span class="punctuation">)</span> <span class="operator">=</span><span class="punctuation">&gt;</span> <span class="punctuation">(</span><span class="punctuation">{</span> 39 <span class="punctuation">(</span><span class="punctuation">$</span><span class="punctuation">(</span><span class="punctuation">$</span>arg<span class="punctuation">:</span>tt<span class="punctuation">)</span><span class="punctuation">*</span><span class="punctuation">)</span> <span class="operator">=</span><span class="punctuation">&gt;</span> <span class="punctuation">(</span><span class="punctuation">{</span>
40 <span class="punctuation">$</span><span class="keyword">crate</span><span class="punctuation">:</span><span class="punctuation">:</span>io<span class="punctuation">:</span><span class="punctuation">:</span>_print<span class="punctuation">(</span><span class="punctuation">$</span><span class="keyword">crate</span><span class="punctuation">:</span><span class="punctuation">:</span>format_args_nl<span class="punctuation">!</span><span class="punctuation">(</span><span class="punctuation">$</span><span class="punctuation">(</span><span class="punctuation">$</span>arg<span class="punctuation">)</span><span class="punctuation">*</span><span class="punctuation">)</span><span class="punctuation">)</span><span class="punctuation">;</span> 40 <span class="punctuation">$</span>crate<span class="punctuation">:</span><span class="punctuation">:</span>io<span class="punctuation">:</span><span class="punctuation">:</span>_print<span class="punctuation">(</span><span class="punctuation">$</span>crate<span class="punctuation">:</span><span class="punctuation">:</span>format_args_nl<span class="punctuation">!</span><span class="punctuation">(</span><span class="punctuation">$</span><span class="punctuation">(</span><span class="punctuation">$</span>arg<span class="punctuation">)</span><span class="punctuation">*</span><span class="punctuation">)</span><span class="punctuation">)</span><span class="punctuation">;</span>
41 <span class="punctuation">}</span><span class="punctuation">)</span> 41 <span class="punctuation">}</span><span class="punctuation">)</span>
42<span class="punctuation">}</span> 42<span class="punctuation">}</span>
43#[rustc_builtin_macro] 43#[rustc_builtin_macro]
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlighting.html b/crates/ide/src/syntax_highlighting/test_data/highlighting.html
index 1d8a3c404..0bb0928e4 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlighting.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlighting.html
@@ -62,7 +62,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
62 62
63<span class="keyword">impl</span> <span class="struct">Foo</span> <span class="punctuation">{</span> 63<span class="keyword">impl</span> <span class="struct">Foo</span> <span class="punctuation">{</span>
64 <span class="keyword">fn</span> <span class="function declaration">baz</span><span class="punctuation">(</span><span class="keyword">mut</span> <span class="self_keyword mutable">self</span><span class="punctuation">,</span> <span class="value_param declaration">f</span><span class="punctuation">:</span> <span class="struct">Foo</span><span class="punctuation">)</span> <span class="operator">-&gt;</span> <span class="builtin_type">i32</span> <span class="punctuation">{</span> 64 <span class="keyword">fn</span> <span class="function declaration">baz</span><span class="punctuation">(</span><span class="keyword">mut</span> <span class="self_keyword mutable">self</span><span class="punctuation">,</span> <span class="value_param declaration">f</span><span class="punctuation">:</span> <span class="struct">Foo</span><span class="punctuation">)</span> <span class="operator">-&gt;</span> <span class="builtin_type">i32</span> <span class="punctuation">{</span>
65 <span class="value_param">f</span><span class="punctuation">.</span><span class="function consuming">baz</span><span class="punctuation">(</span><span class="self_keyword consuming">self</span><span class="punctuation">)</span> 65 <span class="value_param">f</span><span class="punctuation">.</span><span class="function consuming">baz</span><span class="punctuation">(</span><span class="self_keyword mutable consuming">self</span><span class="punctuation">)</span>
66 <span class="punctuation">}</span> 66 <span class="punctuation">}</span>
67 67
68 <span class="keyword">fn</span> <span class="function declaration">qux</span><span class="punctuation">(</span><span class="operator">&</span><span class="keyword">mut</span> <span class="self_keyword mutable">self</span><span class="punctuation">)</span> <span class="punctuation">{</span> 68 <span class="keyword">fn</span> <span class="function declaration">qux</span><span class="punctuation">(</span><span class="operator">&</span><span class="keyword">mut</span> <span class="self_keyword mutable">self</span><span class="punctuation">)</span> <span class="punctuation">{</span>
@@ -115,6 +115,10 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
115 <span class="punctuation">}</span> 115 <span class="punctuation">}</span>
116<span class="punctuation">}</span> 116<span class="punctuation">}</span>
117 117
118<span class="macro">macro_rules!</span> <span class="macro declaration">keyword_frag</span> <span class="punctuation">{</span>
119 <span class="punctuation">(</span><span class="punctuation">$</span>type<span class="punctuation">:</span>ty<span class="punctuation">)</span> <span class="operator">=</span><span class="punctuation">&gt;</span> <span class="punctuation">(</span><span class="punctuation">$</span>type<span class="punctuation">)</span>
120<span class="punctuation">}</span>
121
118<span class="comment">// comment</span> 122<span class="comment">// comment</span>
119<span class="keyword">fn</span> <span class="function declaration">main</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="punctuation">{</span> 123<span class="keyword">fn</span> <span class="function declaration">main</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="punctuation">{</span>
120 <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"Hello, {}!"</span><span class="punctuation">,</span> <span class="numeric_literal">92</span><span class="punctuation">)</span><span class="punctuation">;</span> 124 <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"Hello, {}!"</span><span class="punctuation">,</span> <span class="numeric_literal">92</span><span class="punctuation">)</span><span class="punctuation">;</span>
diff --git a/crates/ide/src/syntax_highlighting/tests.rs b/crates/ide/src/syntax_highlighting/tests.rs
index 694c4b7fa..126363b8b 100644
--- a/crates/ide/src/syntax_highlighting/tests.rs
+++ b/crates/ide/src/syntax_highlighting/tests.rs
@@ -89,6 +89,10 @@ macro_rules! noop {
89 } 89 }
90} 90}
91 91
92macro_rules! keyword_frag {
93 ($type:ty) => ($type)
94}
95
92// comment 96// comment
93fn main() { 97fn main() {
94 println!("Hello, {}!", 92); 98 println!("Hello, {}!", 92);
diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs
index 06b38d99c..fb18f9014 100644
--- a/crates/rust-analyzer/src/main_loop.rs
+++ b/crates/rust-analyzer/src/main_loop.rs
@@ -7,6 +7,7 @@ use std::{
7 7
8use base_db::VfsPath; 8use base_db::VfsPath;
9use crossbeam_channel::{select, Receiver}; 9use crossbeam_channel::{select, Receiver};
10use ide::PrimeCachesProgress;
10use ide::{Canceled, FileId}; 11use ide::{Canceled, FileId};
11use lsp_server::{Connection, Notification, Request, Response}; 12use lsp_server::{Connection, Notification, Request, Response};
12use lsp_types::notification::Notification as _; 13use lsp_types::notification::Notification as _;
@@ -61,7 +62,7 @@ pub(crate) enum Task {
61 Response(Response), 62 Response(Response),
62 Diagnostics(Vec<(FileId, Vec<lsp_types::Diagnostic>)>), 63 Diagnostics(Vec<(FileId, Vec<lsp_types::Diagnostic>)>),
63 Workspaces(Vec<anyhow::Result<ProjectWorkspace>>), 64 Workspaces(Vec<anyhow::Result<ProjectWorkspace>>),
64 Unit, 65 PrimeCaches(PrimeCachesProgress),
65} 66}
66 67
67impl fmt::Debug for Event { 68impl fmt::Debug for Event {
@@ -197,7 +198,28 @@ impl GlobalState {
197 } 198 }
198 } 199 }
199 Task::Workspaces(workspaces) => self.switch_workspaces(workspaces), 200 Task::Workspaces(workspaces) => self.switch_workspaces(workspaces),
200 Task::Unit => (), 201 Task::PrimeCaches(progress) => {
202 let (state, message, fraction);
203 match progress {
204 PrimeCachesProgress::Started => {
205 state = Progress::Begin;
206 message = None;
207 fraction = 0.0;
208 }
209 PrimeCachesProgress::StartedOnCrate { on_crate, n_done, n_total } => {
210 state = Progress::Report;
211 message = Some(format!("{}/{} ({})", n_done, n_total, on_crate));
212 fraction = Progress::fraction(n_done, n_total);
213 }
214 PrimeCachesProgress::Finished => {
215 state = Progress::End;
216 message = None;
217 fraction = 1.0;
218 }
219 };
220
221 self.report_progress("indexing", state, message, Some(fraction));
222 }
201 }, 223 },
202 Event::Vfs(mut task) => { 224 Event::Vfs(mut task) => {
203 let _p = profile::span("GlobalState::handle_event/vfs"); 225 let _p = profile::span("GlobalState::handle_event/vfs");
@@ -573,12 +595,18 @@ impl GlobalState {
573 Task::Diagnostics(diagnostics) 595 Task::Diagnostics(diagnostics)
574 }) 596 })
575 } 597 }
576 self.task_pool.handle.spawn({ 598 self.task_pool.handle.spawn_with_sender({
577 let subs = subscriptions;
578 let snap = self.snapshot(); 599 let snap = self.snapshot();
579 move || { 600 move |sender| {
580 snap.analysis.prime_caches(subs).unwrap_or_else(|_: Canceled| ()); 601 snap.analysis
581 Task::Unit 602 .prime_caches(|progress| {
603 sender.send(Task::PrimeCaches(progress)).unwrap();
604 })
605 .unwrap_or_else(|_: Canceled| {
606 // Pretend that we're done, so that the progress bar is removed. Otherwise
607 // the editor may complain about it already existing.
608 sender.send(Task::PrimeCaches(PrimeCachesProgress::Finished)).unwrap()
609 });
582 } 610 }
583 }); 611 });
584 } 612 }
diff --git a/crates/rust-analyzer/src/thread_pool.rs b/crates/rust-analyzer/src/thread_pool.rs
index 4fa502925..833893739 100644
--- a/crates/rust-analyzer/src/thread_pool.rs
+++ b/crates/rust-analyzer/src/thread_pool.rs
@@ -23,6 +23,17 @@ impl<T> TaskPool<T> {
23 }) 23 })
24 } 24 }
25 25
26 pub(crate) fn spawn_with_sender<F>(&mut self, task: F)
27 where
28 F: FnOnce(Sender<T>) + Send + 'static,
29 T: Send + 'static,
30 {
31 self.inner.execute({
32 let sender = self.sender.clone();
33 move || task(sender)
34 })
35 }
36
26 pub(crate) fn len(&self) -> usize { 37 pub(crate) fn len(&self) -> usize {
27 self.inner.queued_count() 38 self.inner.queued_count()
28 } 39 }
diff --git a/crates/syntax/src/ast/make.rs b/crates/syntax/src/ast/make.rs
index 3a184094c..74dbdfaf7 100644
--- a/crates/syntax/src/ast/make.rs
+++ b/crates/syntax/src/ast/make.rs
@@ -320,6 +320,10 @@ pub fn param(name: String, ty: String) -> ast::Param {
320 ast_from_text(&format!("fn f({}: {}) {{ }}", name, ty)) 320 ast_from_text(&format!("fn f({}: {}) {{ }}", name, ty))
321} 321}
322 322
323pub fn ret_type(ty: ast::Type) -> ast::RetType {
324 ast_from_text(&format!("fn f() -> {} {{ }}", ty))
325}
326
323pub fn param_list(pats: impl IntoIterator<Item = ast::Param>) -> ast::ParamList { 327pub fn param_list(pats: impl IntoIterator<Item = ast::Param>) -> ast::ParamList {
324 let args = pats.into_iter().join(", "); 328 let args = pats.into_iter().join(", ");
325 ast_from_text(&format!("fn f({}) {{ }}", args)) 329 ast_from_text(&format!("fn f({}) {{ }}", args))
@@ -350,14 +354,20 @@ pub fn fn_(
350 type_params: Option<ast::GenericParamList>, 354 type_params: Option<ast::GenericParamList>,
351 params: ast::ParamList, 355 params: ast::ParamList,
352 body: ast::BlockExpr, 356 body: ast::BlockExpr,
357 ret_type: Option<ast::RetType>,
353) -> ast::Fn { 358) -> ast::Fn {
354 let type_params = 359 let type_params =
355 if let Some(type_params) = type_params { format!("<{}>", type_params) } else { "".into() }; 360 if let Some(type_params) = type_params { format!("<{}>", type_params) } else { "".into() };
361 let ret_type = if let Some(ret_type) = ret_type { format!("{} ", ret_type) } else { "".into() };
356 let visibility = match visibility { 362 let visibility = match visibility {
357 None => String::new(), 363 None => String::new(),
358 Some(it) => format!("{} ", it), 364 Some(it) => format!("{} ", it),
359 }; 365 };
360 ast_from_text(&format!("{}fn {}{}{} {}", visibility, fn_name, type_params, params, body)) 366
367 ast_from_text(&format!(
368 "{}fn {}{}{} {}{}",
369 visibility, fn_name, type_params, params, ret_type, body
370 ))
361} 371}
362 372
363fn ast_from_text<N: AstNode>(text: &str) -> N { 373fn ast_from_text<N: AstNode>(text: &str) -> N {