aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock24
-rw-r--r--crates/ra_db/src/fixture.rs4
-rw-r--r--crates/ra_hir/src/code_model.rs18
-rw-r--r--crates/ra_hir_def/src/lang_item.rs2
-rw-r--r--crates/ra_hir_def/src/nameres/raw.rs2
-rw-r--r--crates/ra_hir_expand/src/proc_macro.rs2
-rw-r--r--crates/ra_hir_ty/src/traits/builtin.rs3
-rw-r--r--crates/ra_ide/src/completion/complete_attribute.rs6
-rw-r--r--crates/ra_ide/src/completion/complete_postfix.rs59
-rw-r--r--crates/ra_ide/src/completion/complete_trait_impl.rs61
-rw-r--r--crates/ra_ide/src/display.rs3
-rw-r--r--crates/ra_ide/src/hover.rs16
-rw-r--r--crates/ra_ide/src/ssr.rs8
-rw-r--r--crates/ra_syntax/Cargo.toml2
-rw-r--r--crates/rust-analyzer/tests/heavy_tests/main.rs2
-rw-r--r--docs/dev/lsp-extensions.md63
-rw-r--r--editors/code/rust.tmGrammar.json2
-rw-r--r--editors/code/src/util.ts9
18 files changed, 204 insertions, 82 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 1f4c0cb53..6f3d1f564 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -610,9 +610,9 @@ checksum = "b294d6fa9ee409a054354afc4352b0b9ef7ca222c69b8812cbea9e7d2bf3783f"
610 610
611[[package]] 611[[package]]
612name = "libc" 612name = "libc"
613version = "0.2.70" 613version = "0.2.71"
614source = "registry+https://github.com/rust-lang/crates.io-index" 614source = "registry+https://github.com/rust-lang/crates.io-index"
615checksum = "3baa92041a6fec78c687fa0cc2b3fae8884f743d672cf551bed1d6dac6988d0f" 615checksum = "9457b06509d27052635f90d6466700c65095fdf75409b3fbdd903e988b886f49"
616 616
617[[package]] 617[[package]]
618name = "libloading" 618name = "libloading"
@@ -830,9 +830,9 @@ dependencies = [
830 830
831[[package]] 831[[package]]
832name = "paste" 832name = "paste"
833version = "0.1.13" 833version = "0.1.14"
834source = "registry+https://github.com/rust-lang/crates.io-index" 834source = "registry+https://github.com/rust-lang/crates.io-index"
835checksum = "678f27e19361472a23717f11d229a7522ef64605baf0715c896a94b8b6b13a06" 835checksum = "3431e8f72b90f8a7af91dec890d9814000cb371258e0ec7370d93e085361f531"
836dependencies = [ 836dependencies = [
837 "paste-impl", 837 "paste-impl",
838 "proc-macro-hack", 838 "proc-macro-hack",
@@ -840,9 +840,9 @@ dependencies = [
840 840
841[[package]] 841[[package]]
842name = "paste-impl" 842name = "paste-impl"
843version = "0.1.13" 843version = "0.1.14"
844source = "registry+https://github.com/rust-lang/crates.io-index" 844source = "registry+https://github.com/rust-lang/crates.io-index"
845checksum = "149089128a45d8e377677b08873b4bad2a56618f80e4f28a83862ba250994a30" 845checksum = "25af5fc872ba284d8d84608bf8a0fa9b5376c96c23f503b007dfd9e34dde5606"
846dependencies = [ 846dependencies = [
847 "proc-macro-hack", 847 "proc-macro-hack",
848 "proc-macro2", 848 "proc-macro2",
@@ -886,9 +886,9 @@ checksum = "237a5ed80e274dbc66f86bd59c1e25edc039660be53194b5fe0a482e0f2612ea"
886 886
887[[package]] 887[[package]]
888name = "proc-macro-hack" 888name = "proc-macro-hack"
889version = "0.5.15" 889version = "0.5.16"
890source = "registry+https://github.com/rust-lang/crates.io-index" 890source = "registry+https://github.com/rust-lang/crates.io-index"
891checksum = "0d659fe7c6d27f25e9d80a1a094c223f5246f6a6596453e09d7229bf42750b63" 891checksum = "7e0456befd48169b9f13ef0f0ad46d492cf9d2dbb918bcf38e01eed4ce3ec5e4"
892 892
893[[package]] 893[[package]]
894name = "proc-macro2" 894name = "proc-macro2"
@@ -1401,9 +1401,9 @@ dependencies = [
1401 1401
1402[[package]] 1402[[package]]
1403name = "rustc-ap-rustc_lexer" 1403name = "rustc-ap-rustc_lexer"
1404version = "660.0.0" 1404version = "661.0.0"
1405source = "registry+https://github.com/rust-lang/crates.io-index" 1405source = "registry+https://github.com/rust-lang/crates.io-index"
1406checksum = "30760dbcc7667c9e0da561e980e24867ca7f4526ce060a3d7e6d9dcfeaae88d1" 1406checksum = "a6d88abd7c634b52557e46fc7ba47644f0cbe45c358c33f51c532d60d1da239e"
1407dependencies = [ 1407dependencies = [
1408 "unicode-xid", 1408 "unicode-xid",
1409] 1409]
@@ -1598,9 +1598,9 @@ checksum = "ab16ced94dbd8a46c82fd81e3ed9a8727dac2977ea869d217bcc4ea1f122e81f"
1598 1598
1599[[package]] 1599[[package]]
1600name = "syn" 1600name = "syn"
1601version = "1.0.23" 1601version = "1.0.25"
1602source = "registry+https://github.com/rust-lang/crates.io-index" 1602source = "registry+https://github.com/rust-lang/crates.io-index"
1603checksum = "95b5f192649e48a5302a13f2feb224df883b98933222369e4b3b0fe2a5447269" 1603checksum = "f14a640819f79b72a710c0be059dce779f9339ae046c8bef12c361d56702146f"
1604dependencies = [ 1604dependencies = [
1605 "proc-macro2", 1605 "proc-macro2",
1606 "quote", 1606 "quote",
diff --git a/crates/ra_db/src/fixture.rs b/crates/ra_db/src/fixture.rs
index f6b50c67c..482a2f3e6 100644
--- a/crates/ra_db/src/fixture.rs
+++ b/crates/ra_db/src/fixture.rs
@@ -267,8 +267,8 @@ impl From<&FixtureMeta> for ParsedMeta {
267 ParsedMeta::Root { path: path.to_owned() } 267 ParsedMeta::Root { path: path.to_owned() }
268 } 268 }
269 FixtureMeta::File(f) => Self::File(FileMeta { 269 FixtureMeta::File(f) => Self::File(FileMeta {
270 path: f.path.to_owned().into(), 270 path: f.path.to_owned(),
271 krate: f.crate_name.to_owned().into(), 271 krate: f.crate_name.to_owned(),
272 deps: f.deps.to_owned(), 272 deps: f.deps.to_owned(),
273 cfg: f.cfg.to_owned(), 273 cfg: f.cfg.to_owned(),
274 edition: f 274 edition: f
diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs
index 840cfdfc8..8d7937d94 100644
--- a/crates/ra_hir/src/code_model.rs
+++ b/crates/ra_hir/src/code_model.rs
@@ -532,7 +532,7 @@ impl Adt {
532 Some(self.module(db).krate()) 532 Some(self.module(db).krate())
533 } 533 }
534 534
535 pub fn name(&self, db: &dyn HirDatabase) -> Name { 535 pub fn name(self, db: &dyn HirDatabase) -> Name {
536 match self { 536 match self {
537 Adt::Struct(s) => s.name(db), 537 Adt::Struct(s) => s.name(db),
538 Adt::Union(u) => u.name(db), 538 Adt::Union(u) => u.name(db),
@@ -1018,15 +1018,15 @@ impl ImplDef {
1018 impls.lookup_impl_defs_for_trait(trait_.id).map(Self::from).collect() 1018 impls.lookup_impl_defs_for_trait(trait_.id).map(Self::from).collect()
1019 } 1019 }
1020 1020
1021 pub fn target_trait(&self, db: &dyn HirDatabase) -> Option<TypeRef> { 1021 pub fn target_trait(self, db: &dyn HirDatabase) -> Option<TypeRef> {
1022 db.impl_data(self.id).target_trait.clone() 1022 db.impl_data(self.id).target_trait.clone()
1023 } 1023 }
1024 1024
1025 pub fn target_type(&self, db: &dyn HirDatabase) -> TypeRef { 1025 pub fn target_type(self, db: &dyn HirDatabase) -> TypeRef {
1026 db.impl_data(self.id).target_type.clone() 1026 db.impl_data(self.id).target_type.clone()
1027 } 1027 }
1028 1028
1029 pub fn target_ty(&self, db: &dyn HirDatabase) -> Type { 1029 pub fn target_ty(self, db: &dyn HirDatabase) -> Type {
1030 let impl_data = db.impl_data(self.id); 1030 let impl_data = db.impl_data(self.id);
1031 let resolver = self.id.resolver(db.upcast()); 1031 let resolver = self.id.resolver(db.upcast());
1032 let ctx = hir_ty::TyLoweringContext::new(db, &resolver); 1032 let ctx = hir_ty::TyLoweringContext::new(db, &resolver);
@@ -1038,23 +1038,23 @@ impl ImplDef {
1038 } 1038 }
1039 } 1039 }
1040 1040
1041 pub fn items(&self, db: &dyn HirDatabase) -> Vec<AssocItem> { 1041 pub fn items(self, db: &dyn HirDatabase) -> Vec<AssocItem> {
1042 db.impl_data(self.id).items.iter().map(|it| (*it).into()).collect() 1042 db.impl_data(self.id).items.iter().map(|it| (*it).into()).collect()
1043 } 1043 }
1044 1044
1045 pub fn is_negative(&self, db: &dyn HirDatabase) -> bool { 1045 pub fn is_negative(self, db: &dyn HirDatabase) -> bool {
1046 db.impl_data(self.id).is_negative 1046 db.impl_data(self.id).is_negative
1047 } 1047 }
1048 1048
1049 pub fn module(&self, db: &dyn HirDatabase) -> Module { 1049 pub fn module(self, db: &dyn HirDatabase) -> Module {
1050 self.id.lookup(db.upcast()).container.module(db.upcast()).into() 1050 self.id.lookup(db.upcast()).container.module(db.upcast()).into()
1051 } 1051 }
1052 1052
1053 pub fn krate(&self, db: &dyn HirDatabase) -> Crate { 1053 pub fn krate(self, db: &dyn HirDatabase) -> Crate {
1054 Crate { id: self.module(db).id.krate } 1054 Crate { id: self.module(db).id.krate }
1055 } 1055 }
1056 1056
1057 pub fn is_builtin_derive(&self, db: &dyn HirDatabase) -> Option<InFile<ast::Attr>> { 1057 pub fn is_builtin_derive(self, db: &dyn HirDatabase) -> Option<InFile<ast::Attr>> {
1058 let src = self.source(db); 1058 let src = self.source(db);
1059 let item = src.file_id.is_builtin_derive(db.upcast())?; 1059 let item = src.file_id.is_builtin_derive(db.upcast())?;
1060 let hygenic = hir_expand::hygiene::Hygiene::new(db.upcast(), item.file_id); 1060 let hygenic = hir_expand::hygiene::Hygiene::new(db.upcast(), item.file_id);
diff --git a/crates/ra_hir_def/src/lang_item.rs b/crates/ra_hir_def/src/lang_item.rs
index d962db3cc..3516784b8 100644
--- a/crates/ra_hir_def/src/lang_item.rs
+++ b/crates/ra_hir_def/src/lang_item.rs
@@ -164,7 +164,7 @@ impl LangItems {
164 T: Into<AttrDefId> + Copy, 164 T: Into<AttrDefId> + Copy,
165 { 165 {
166 if let Some(lang_item_name) = lang_attr(db, item) { 166 if let Some(lang_item_name) = lang_attr(db, item) {
167 self.items.entry(lang_item_name.clone()).or_insert_with(|| constructor(item)); 167 self.items.entry(lang_item_name).or_insert_with(|| constructor(item));
168 } 168 }
169 } 169 }
170} 170}
diff --git a/crates/ra_hir_def/src/nameres/raw.rs b/crates/ra_hir_def/src/nameres/raw.rs
index 4e628b14d..f44baa579 100644
--- a/crates/ra_hir_def/src/nameres/raw.rs
+++ b/crates/ra_hir_def/src/nameres/raw.rs
@@ -175,7 +175,7 @@ pub(super) enum DefKind {
175} 175}
176 176
177impl DefKind { 177impl DefKind {
178 pub fn ast_id(&self) -> FileAstId<ast::ModuleItem> { 178 pub fn ast_id(self) -> FileAstId<ast::ModuleItem> {
179 match self { 179 match self {
180 DefKind::Function(it) => it.upcast(), 180 DefKind::Function(it) => it.upcast(),
181 DefKind::Struct(it, _) => it.upcast(), 181 DefKind::Struct(it, _) => it.upcast(),
diff --git a/crates/ra_hir_expand/src/proc_macro.rs b/crates/ra_hir_expand/src/proc_macro.rs
index 4e0e069c8..04c026004 100644
--- a/crates/ra_hir_expand/src/proc_macro.rs
+++ b/crates/ra_hir_expand/src/proc_macro.rs
@@ -25,7 +25,7 @@ impl ProcMacroExpander {
25 } 25 }
26 26
27 pub fn expand( 27 pub fn expand(
28 &self, 28 self,
29 db: &dyn AstDatabase, 29 db: &dyn AstDatabase,
30 _id: LazyMacroId, 30 _id: LazyMacroId,
31 tt: &tt::Subtree, 31 tt: &tt::Subtree,
diff --git a/crates/ra_hir_ty/src/traits/builtin.rs b/crates/ra_hir_ty/src/traits/builtin.rs
index ccab246bf..88a422d2c 100644
--- a/crates/ra_hir_ty/src/traits/builtin.rs
+++ b/crates/ra_hir_ty/src/traits/builtin.rs
@@ -290,8 +290,7 @@ fn trait_object_unsize_impl_datum(
290 let self_trait_ref = TraitRef { trait_, substs: self_substs }; 290 let self_trait_ref = TraitRef { trait_, substs: self_substs };
291 let where_clauses = vec![GenericPredicate::Implemented(self_trait_ref)]; 291 let where_clauses = vec![GenericPredicate::Implemented(self_trait_ref)];
292 292
293 let impl_substs = 293 let impl_substs = Substs::builder(2).push(self_ty).push(Ty::Dyn(target_bounds.into())).build();
294 Substs::builder(2).push(self_ty).push(Ty::Dyn(target_bounds.clone().into())).build();
295 294
296 let trait_ref = TraitRef { trait_: unsize_trait, substs: impl_substs }; 295 let trait_ref = TraitRef { trait_: unsize_trait, substs: impl_substs };
297 296
diff --git a/crates/ra_ide/src/completion/complete_attribute.rs b/crates/ra_ide/src/completion/complete_attribute.rs
index f17266221..fb3f0b743 100644
--- a/crates/ra_ide/src/completion/complete_attribute.rs
+++ b/crates/ra_ide/src/completion/complete_attribute.rs
@@ -112,7 +112,7 @@ const ATTRIBUTES: &[AttrCompletion] = &[
112 AttrCompletion { label: "repr", snippet: Some("repr(${0:C})"), should_be_inner: false }, 112 AttrCompletion { label: "repr", snippet: Some("repr(${0:C})"), should_be_inner: false },
113 AttrCompletion { 113 AttrCompletion {
114 label: "should_panic", 114 label: "should_panic",
115 snippet: Some(r#"expected = "${0:reason}""#), 115 snippet: Some(r#"should_panic(expected = "${0:reason}")"#),
116 should_be_inner: false, 116 should_be_inner: false,
117 }, 117 },
118 AttrCompletion { 118 AttrCompletion {
@@ -571,7 +571,7 @@ mod tests {
571 label: "should_panic", 571 label: "should_panic",
572 source_range: 19..19, 572 source_range: 19..19,
573 delete: 19..19, 573 delete: 19..19,
574 insert: "expected = \"${0:reason}\"", 574 insert: "should_panic(expected = \"${0:reason}\")",
575 kind: Attribute, 575 kind: Attribute,
576 }, 576 },
577 CompletionItem { 577 CompletionItem {
@@ -810,7 +810,7 @@ mod tests {
810 label: "should_panic", 810 label: "should_panic",
811 source_range: 20..20, 811 source_range: 20..20,
812 delete: 20..20, 812 delete: 20..20,
813 insert: "expected = \"${0:reason}\"", 813 insert: "should_panic(expected = \"${0:reason}\")",
814 kind: Attribute, 814 kind: Attribute,
815 }, 815 },
816 CompletionItem { 816 CompletionItem {
diff --git a/crates/ra_ide/src/completion/complete_postfix.rs b/crates/ra_ide/src/completion/complete_postfix.rs
index f2a52a407..02e660ca8 100644
--- a/crates/ra_ide/src/completion/complete_postfix.rs
+++ b/crates/ra_ide/src/completion/complete_postfix.rs
@@ -184,6 +184,16 @@ pub(super) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) {
184 &format!("dbg!({})", receiver_text), 184 &format!("dbg!({})", receiver_text),
185 ) 185 )
186 .add_to(acc); 186 .add_to(acc);
187
188 postfix_snippet(
189 ctx,
190 cap,
191 &dot_receiver,
192 "call",
193 "function(expr)",
194 &format!("${{1}}({})", receiver_text),
195 )
196 .add_to(acc);
187} 197}
188 198
189fn get_receiver_text(receiver: &ast::Expr, receiver_is_ambiguous_float_literal: bool) -> String { 199fn get_receiver_text(receiver: &ast::Expr, receiver_is_ambiguous_float_literal: bool) -> String {
@@ -256,6 +266,13 @@ mod tests {
256 detail: "Box::new(expr)", 266 detail: "Box::new(expr)",
257 }, 267 },
258 CompletionItem { 268 CompletionItem {
269 label: "call",
270 source_range: 89..89,
271 delete: 85..89,
272 insert: "${1}(bar)",
273 detail: "function(expr)",
274 },
275 CompletionItem {
259 label: "dbg", 276 label: "dbg",
260 source_range: 89..89, 277 source_range: 89..89,
261 delete: 85..89, 278 delete: 85..89,
@@ -335,6 +352,13 @@ mod tests {
335 detail: "Box::new(expr)", 352 detail: "Box::new(expr)",
336 }, 353 },
337 CompletionItem { 354 CompletionItem {
355 label: "call",
356 source_range: 210..210,
357 delete: 206..210,
358 insert: "${1}(bar)",
359 detail: "function(expr)",
360 },
361 CompletionItem {
338 label: "dbg", 362 label: "dbg",
339 source_range: 210..210, 363 source_range: 210..210,
340 delete: 206..210, 364 delete: 206..210,
@@ -414,6 +438,13 @@ mod tests {
414 detail: "Box::new(expr)", 438 detail: "Box::new(expr)",
415 }, 439 },
416 CompletionItem { 440 CompletionItem {
441 label: "call",
442 source_range: 211..211,
443 delete: 207..211,
444 insert: "${1}(bar)",
445 detail: "function(expr)",
446 },
447 CompletionItem {
417 label: "dbg", 448 label: "dbg",
418 source_range: 211..211, 449 source_range: 211..211,
419 delete: 207..211, 450 delete: 207..211,
@@ -488,6 +519,13 @@ mod tests {
488 detail: "Box::new(expr)", 519 detail: "Box::new(expr)",
489 }, 520 },
490 CompletionItem { 521 CompletionItem {
522 label: "call",
523 source_range: 91..91,
524 delete: 87..91,
525 insert: "${1}(bar)",
526 detail: "function(expr)",
527 },
528 CompletionItem {
491 label: "dbg", 529 label: "dbg",
492 source_range: 91..91, 530 source_range: 91..91,
493 delete: 87..91, 531 delete: 87..91,
@@ -547,6 +585,13 @@ mod tests {
547 detail: "Box::new(expr)", 585 detail: "Box::new(expr)",
548 }, 586 },
549 CompletionItem { 587 CompletionItem {
588 label: "call",
589 source_range: 52..52,
590 delete: 49..52,
591 insert: "${1}(42)",
592 detail: "function(expr)",
593 },
594 CompletionItem {
550 label: "dbg", 595 label: "dbg",
551 source_range: 52..52, 596 source_range: 52..52,
552 delete: 49..52, 597 delete: 49..52,
@@ -608,6 +653,13 @@ mod tests {
608 detail: "Box::new(expr)", 653 detail: "Box::new(expr)",
609 }, 654 },
610 CompletionItem { 655 CompletionItem {
656 label: "call",
657 source_range: 149..150,
658 delete: 145..150,
659 insert: "${1}(bar)",
660 detail: "function(expr)",
661 },
662 CompletionItem {
611 label: "dbg", 663 label: "dbg",
612 source_range: 149..150, 664 source_range: 149..150,
613 delete: 145..150, 665 delete: 145..150,
@@ -667,6 +719,13 @@ mod tests {
667 detail: "Box::new(expr)", 719 detail: "Box::new(expr)",
668 }, 720 },
669 CompletionItem { 721 CompletionItem {
722 label: "call",
723 source_range: 56..56,
724 delete: 49..56,
725 insert: "${1}(&&&&42)",
726 detail: "function(expr)",
727 },
728 CompletionItem {
670 label: "dbg", 729 label: "dbg",
671 source_range: 56..56, 730 source_range: 56..56,
672 delete: 49..56, 731 delete: 49..56,
diff --git a/crates/ra_ide/src/completion/complete_trait_impl.rs b/crates/ra_ide/src/completion/complete_trait_impl.rs
index 039df03e0..21c9316e6 100644
--- a/crates/ra_ide/src/completion/complete_trait_impl.rs
+++ b/crates/ra_ide/src/completion/complete_trait_impl.rs
@@ -49,56 +49,53 @@ use crate::{
49pub(crate) fn complete_trait_impl(acc: &mut Completions, ctx: &CompletionContext) { 49pub(crate) fn complete_trait_impl(acc: &mut Completions, ctx: &CompletionContext) {
50 if let Some((trigger, impl_def)) = completion_match(ctx) { 50 if let Some((trigger, impl_def)) = completion_match(ctx) {
51 match trigger.kind() { 51 match trigger.kind() {
52 SyntaxKind::NAME_REF => { 52 SyntaxKind::NAME_REF => get_missing_assoc_items(&ctx.sema, &impl_def)
53 get_missing_assoc_items(&ctx.sema, &impl_def).iter().for_each(|item| match item { 53 .into_iter()
54 .for_each(|item| match item {
54 hir::AssocItem::Function(fn_item) => { 55 hir::AssocItem::Function(fn_item) => {
55 add_function_impl(&trigger, acc, ctx, &fn_item) 56 add_function_impl(&trigger, acc, ctx, fn_item)
56 } 57 }
57 hir::AssocItem::TypeAlias(type_item) => { 58 hir::AssocItem::TypeAlias(type_item) => {
58 add_type_alias_impl(&trigger, acc, ctx, &type_item) 59 add_type_alias_impl(&trigger, acc, ctx, type_item)
59 } 60 }
60 hir::AssocItem::Const(const_item) => { 61 hir::AssocItem::Const(const_item) => {
61 add_const_impl(&trigger, acc, ctx, &const_item) 62 add_const_impl(&trigger, acc, ctx, const_item)
62 } 63 }
63 }) 64 }),
64 }
65 65
66 SyntaxKind::FN_DEF => { 66 SyntaxKind::FN_DEF => {
67 for missing_fn in 67 for missing_fn in get_missing_assoc_items(&ctx.sema, &impl_def)
68 get_missing_assoc_items(&ctx.sema, &impl_def).iter().filter_map(|item| { 68 .into_iter()
69 match item { 69 .filter_map(|item| match item {
70 hir::AssocItem::Function(fn_item) => Some(fn_item), 70 hir::AssocItem::Function(fn_item) => Some(fn_item),
71 _ => None, 71 _ => None,
72 }
73 }) 72 })
74 { 73 {
75 add_function_impl(&trigger, acc, ctx, &missing_fn); 74 add_function_impl(&trigger, acc, ctx, missing_fn);
76 } 75 }
77 } 76 }
78 77
79 SyntaxKind::TYPE_ALIAS_DEF => { 78 SyntaxKind::TYPE_ALIAS_DEF => {
80 for missing_fn in 79 for missing_fn in get_missing_assoc_items(&ctx.sema, &impl_def)
81 get_missing_assoc_items(&ctx.sema, &impl_def).iter().filter_map(|item| { 80 .into_iter()
82 match item { 81 .filter_map(|item| match item {
83 hir::AssocItem::TypeAlias(type_item) => Some(type_item), 82 hir::AssocItem::TypeAlias(type_item) => Some(type_item),
84 _ => None, 83 _ => None,
85 }
86 }) 84 })
87 { 85 {
88 add_type_alias_impl(&trigger, acc, ctx, &missing_fn); 86 add_type_alias_impl(&trigger, acc, ctx, missing_fn);
89 } 87 }
90 } 88 }
91 89
92 SyntaxKind::CONST_DEF => { 90 SyntaxKind::CONST_DEF => {
93 for missing_fn in 91 for missing_fn in get_missing_assoc_items(&ctx.sema, &impl_def)
94 get_missing_assoc_items(&ctx.sema, &impl_def).iter().filter_map(|item| { 92 .into_iter()
95 match item { 93 .filter_map(|item| match item {
96 hir::AssocItem::Const(const_item) => Some(const_item), 94 hir::AssocItem::Const(const_item) => Some(const_item),
97 _ => None, 95 _ => None,
98 }
99 }) 96 })
100 { 97 {
101 add_const_impl(&trigger, acc, ctx, &missing_fn); 98 add_const_impl(&trigger, acc, ctx, missing_fn);
102 } 99 }
103 } 100 }
104 101
@@ -126,9 +123,9 @@ fn add_function_impl(
126 fn_def_node: &SyntaxNode, 123 fn_def_node: &SyntaxNode,
127 acc: &mut Completions, 124 acc: &mut Completions,
128 ctx: &CompletionContext, 125 ctx: &CompletionContext,
129 func: &hir::Function, 126 func: hir::Function,
130) { 127) {
131 let signature = FunctionSignature::from_hir(ctx.db, *func); 128 let signature = FunctionSignature::from_hir(ctx.db, func);
132 129
133 let fn_name = func.name(ctx.db).to_string(); 130 let fn_name = func.name(ctx.db).to_string();
134 131
@@ -167,7 +164,7 @@ fn add_type_alias_impl(
167 type_def_node: &SyntaxNode, 164 type_def_node: &SyntaxNode,
168 acc: &mut Completions, 165 acc: &mut Completions,
169 ctx: &CompletionContext, 166 ctx: &CompletionContext,
170 type_alias: &hir::TypeAlias, 167 type_alias: hir::TypeAlias,
171) { 168) {
172 let alias_name = type_alias.name(ctx.db).to_string(); 169 let alias_name = type_alias.name(ctx.db).to_string();
173 170
@@ -187,7 +184,7 @@ fn add_const_impl(
187 const_def_node: &SyntaxNode, 184 const_def_node: &SyntaxNode,
188 acc: &mut Completions, 185 acc: &mut Completions,
189 ctx: &CompletionContext, 186 ctx: &CompletionContext,
190 const_: &hir::Const, 187 const_: hir::Const,
191) { 188) {
192 let const_name = const_.name(ctx.db).map(|n| n.to_string()); 189 let const_name = const_.name(ctx.db).map(|n| n.to_string());
193 190
diff --git a/crates/ra_ide/src/display.rs b/crates/ra_ide/src/display.rs
index 8bb312156..827c094e7 100644
--- a/crates/ra_ide/src/display.rs
+++ b/crates/ra_ide/src/display.rs
@@ -83,12 +83,13 @@ pub(crate) fn rust_code_markup_with_doc(
83 83
84 if let Some(mod_path) = mod_path { 84 if let Some(mod_path) = mod_path {
85 if !mod_path.is_empty() { 85 if !mod_path.is_empty() {
86 format_to!(buf, "{}\n___\n\n", mod_path); 86 format_to!(buf, "```rust\n{}\n```\n\n", mod_path);
87 } 87 }
88 } 88 }
89 format_to!(buf, "```rust\n{}\n```", code); 89 format_to!(buf, "```rust\n{}\n```", code);
90 90
91 if let Some(doc) = doc { 91 if let Some(doc) = doc {
92 format_to!(buf, "\n___");
92 format_to!(buf, "\n\n{}", doc); 93 format_to!(buf, "\n\n{}", doc);
93 } 94 }
94 95
diff --git a/crates/ra_ide/src/hover.rs b/crates/ra_ide/src/hover.rs
index 1f4f6b848..3e721dcca 100644
--- a/crates/ra_ide/src/hover.rs
+++ b/crates/ra_ide/src/hover.rs
@@ -405,7 +405,7 @@ mod tests {
405 }; 405 };
406 } 406 }
407 "#, 407 "#,
408 &["Foo\n___\n\n```rust\nfield_a: u32"], 408 &["Foo\n```\n\n```rust\nfield_a: u32"],
409 ); 409 );
410 410
411 // Hovering over the field in the definition 411 // Hovering over the field in the definition
@@ -422,7 +422,7 @@ mod tests {
422 }; 422 };
423 } 423 }
424 "#, 424 "#,
425 &["Foo\n___\n\n```rust\nfield_a: u32"], 425 &["Foo\n```\n\n```rust\nfield_a: u32"],
426 ); 426 );
427 } 427 }
428 428
@@ -475,7 +475,7 @@ fn main() {
475 ", 475 ",
476 ); 476 );
477 let hover = analysis.hover(position).unwrap().unwrap(); 477 let hover = analysis.hover(position).unwrap().unwrap();
478 assert_eq!(trim_markup_opt(hover.info.first()), Some("Option\n___\n\n```rust\nSome")); 478 assert_eq!(trim_markup_opt(hover.info.first()), Some("Option\n```\n\n```rust\nSome"));
479 479
480 let (analysis, position) = single_file_with_position( 480 let (analysis, position) = single_file_with_position(
481 " 481 "
@@ -503,11 +503,12 @@ fn main() {
503 "#, 503 "#,
504 &[" 504 &["
505Option 505Option
506___ 506```
507 507
508```rust 508```rust
509None 509None
510``` 510```
511___
511 512
512The None variant 513The None variant
513 " 514 "
@@ -527,11 +528,12 @@ The None variant
527 "#, 528 "#,
528 &[" 529 &["
529Option 530Option
530___ 531```
531 532
532```rust 533```rust
533Some 534Some
534``` 535```
536___
535 537
536The Some variant 538The Some variant
537 " 539 "
@@ -614,7 +616,7 @@ fn func(foo: i32) { if true { <|>foo; }; }
614 let hover = analysis.hover(position).unwrap().unwrap(); 616 let hover = analysis.hover(position).unwrap().unwrap();
615 assert_eq!( 617 assert_eq!(
616 trim_markup_opt(hover.info.first()), 618 trim_markup_opt(hover.info.first()),
617 Some("wrapper::Thing\n___\n\n```rust\nfn new() -> Thing") 619 Some("wrapper::Thing\n```\n\n```rust\nfn new() -> Thing")
618 ); 620 );
619 } 621 }
620 622
@@ -891,7 +893,7 @@ fn func(foo: i32) { if true { <|>foo; }; }
891 fo<|>o(); 893 fo<|>o();
892 } 894 }
893 ", 895 ",
894 &["fn foo()\n```\n\n<- `\u{3000}` here"], 896 &["fn foo()\n```\n___\n\n<- `\u{3000}` here"],
895 ); 897 );
896 } 898 }
897 899
diff --git a/crates/ra_ide/src/ssr.rs b/crates/ra_ide/src/ssr.rs
index 1873d1d0d..130d3b4c3 100644
--- a/crates/ra_ide/src/ssr.rs
+++ b/crates/ra_ide/src/ssr.rs
@@ -196,10 +196,10 @@ fn find(pattern: &SsrPattern, code: &SyntaxNode) -> SsrMatches {
196 ) -> Option<Match> { 196 ) -> Option<Match> {
197 let match_ = check_opt_nodes(pattern.path(), code.path(), placeholders, match_)?; 197 let match_ = check_opt_nodes(pattern.path(), code.path(), placeholders, match_)?;
198 198
199 let mut pattern_fields = 199 let mut pattern_fields: Vec<RecordField> =
200 pattern.record_field_list().map(|x| x.fields().collect()).unwrap_or(vec![]); 200 pattern.record_field_list().map(|x| x.fields().collect()).unwrap_or_default();
201 let mut code_fields = 201 let mut code_fields: Vec<RecordField> =
202 code.record_field_list().map(|x| x.fields().collect()).unwrap_or(vec![]); 202 code.record_field_list().map(|x| x.fields().collect()).unwrap_or_default();
203 203
204 if pattern_fields.len() != code_fields.len() { 204 if pattern_fields.len() != code_fields.len() {
205 return None; 205 return None;
diff --git a/crates/ra_syntax/Cargo.toml b/crates/ra_syntax/Cargo.toml
index a9a5cc7bc..a8ff2e74f 100644
--- a/crates/ra_syntax/Cargo.toml
+++ b/crates/ra_syntax/Cargo.toml
@@ -13,7 +13,7 @@ doctest = false
13[dependencies] 13[dependencies]
14itertools = "0.9.0" 14itertools = "0.9.0"
15rowan = "0.10.0" 15rowan = "0.10.0"
16rustc_lexer = { version = "660.0.0", package = "rustc-ap-rustc_lexer" } 16rustc_lexer = { version = "661.0.0", package = "rustc-ap-rustc_lexer" }
17rustc-hash = "1.1.0" 17rustc-hash = "1.1.0"
18arrayvec = "0.5.1" 18arrayvec = "0.5.1"
19once_cell = "1.3.1" 19once_cell = "1.3.1"
diff --git a/crates/rust-analyzer/tests/heavy_tests/main.rs b/crates/rust-analyzer/tests/heavy_tests/main.rs
index b1bfc968a..405ddb362 100644
--- a/crates/rust-analyzer/tests/heavy_tests/main.rs
+++ b/crates/rust-analyzer/tests/heavy_tests/main.rs
@@ -756,5 +756,5 @@ pub fn foo(_input: TokenStream) -> TokenStream {
756 }); 756 });
757 757
758 let value = res.get("contents").unwrap().get("value").unwrap().to_string(); 758 let value = res.get("contents").unwrap().get("value").unwrap().to_string();
759 assert_eq!(value, r#""foo::Bar\n___\n\n```rust\nfn bar()\n```""#) 759 assert_eq!(value, r#""```rust\nfoo::Bar\n```\n\n```rust\nfn bar()\n```""#)
760} 760}
diff --git a/docs/dev/lsp-extensions.md b/docs/dev/lsp-extensions.md
index 209f470eb..68a5df27e 100644
--- a/docs/dev/lsp-extensions.md
+++ b/docs/dev/lsp-extensions.md
@@ -362,3 +362,66 @@ interface ExpandedMacro {
362``` 362```
363 363
364Expands macro call at a given position. 364Expands macro call at a given position.
365
366## Inlay Hints
367
368**Method:** `rust-analyzer/inlayHints`
369
370This request is send from client to server to render "inlay hints" -- virtual text inserted into editor to show things like inferred types.
371Generally, the client should re-query inlay hints after every modification.
372Note that we plan to move this request to `experimental/inlayHints`, as it is not really Rust-specific, but the current API is not necessary the right one.
373Upstream issue: https://github.com/microsoft/language-server-protocol/issues/956
374
375**Request:**
376
377```typescript
378interface InlayHintsParams {
379 textDocument: TextDocumentIdentifier,
380}
381```
382
383**Response:** `InlayHint[]`
384
385```typescript
386interface InlayHint {
387 kind: "TypeHint" | "ParameterHint" | "ChainingHint",
388 range: Range,
389 label: string,
390}
391```
392
393## Runnables
394
395**Method:** `rust-analyzer/runnables`
396
397This request is send from client to server to get the list of things that can be run (tests, binaries, `cargo check -p`).
398Note that we plan to move this request to `experimental/runnables`, as it is not really Rust-specific, but the current API is not necessary the right one.
399Upstream issue: https://github.com/microsoft/language-server-protocol/issues/944
400
401**Request:**
402
403```typescript
404interface RunnablesParams {
405 textDocument: TextDocumentIdentifier;
406 /// If null, compute runnables for the whole file.
407 position?: Position;
408}
409```
410
411**Response:** `Runnable[]`
412
413```typescript
414interface Runnable {
415 /// The range this runnable is applicable for.
416 range: lc.Range;
417 /// The label to show in the UI.
418 label: string;
419 /// The following fields describe a process to spawn.
420 bin: string;
421 args: string[];
422 /// Args for cargo after `--`.
423 extraArgs: string[];
424 env: { [key: string]: string };
425 cwd: string | null;
426}
427```
diff --git a/editors/code/rust.tmGrammar.json b/editors/code/rust.tmGrammar.json
index cdcd557dc..ab87cd39f 100644
--- a/editors/code/rust.tmGrammar.json
+++ b/editors/code/rust.tmGrammar.json
@@ -207,7 +207,7 @@
207 { 207 {
208 "comment": "Miscellaneous operator", 208 "comment": "Miscellaneous operator",
209 "name": "keyword.operator.misc.rust", 209 "name": "keyword.operator.misc.rust",
210 "match": "(=>|::)" 210 "match": "(=>|::|\\?)"
211 }, 211 },
212 { 212 {
213 "comment": "Comparison operator", 213 "comment": "Comparison operator",
diff --git a/editors/code/src/util.ts b/editors/code/src/util.ts
index 127a9e911..793c481fb 100644
--- a/editors/code/src/util.ts
+++ b/editors/code/src/util.ts
@@ -74,10 +74,11 @@ export type RustDocument = vscode.TextDocument & { languageId: "rust" };
74export type RustEditor = vscode.TextEditor & { document: RustDocument }; 74export type RustEditor = vscode.TextEditor & { document: RustDocument };
75 75
76export function isRustDocument(document: vscode.TextDocument): document is RustDocument { 76export function isRustDocument(document: vscode.TextDocument): document is RustDocument {
77 return document.languageId === 'rust' 77 // Prevent corrupted text (particularly via inlay hints) in diff views
78 // SCM diff views have the same URI as the on-disk document but not the same content 78 // by allowing only `file` schemes
79 && document.uri.scheme !== 'git' 79 // unfortunately extensions that use diff views not always set this
80 && document.uri.scheme !== 'svn'; 80 // to something different than 'file' (see ongoing bug: #4608)
81 return document.languageId === 'rust' && document.uri.scheme === 'file';
81} 82}
82 83
83export function isRustEditor(editor: vscode.TextEditor): editor is RustEditor { 84export function isRustEditor(editor: vscode.TextEditor): editor is RustEditor {