Repository: rust-analyzer/rust-analyzer (rust)

Issue:
Highlighting the ? operator
When the ? operator was proposed, people have suggested that highlighting it in the IDE would be a good way of ensuring you don't miss it. So far this hasn't really been done, so it would be great if we could have it be semantically (or syntactically?) highlighted.

Pull request description:
Highlight question mark operator
Fixes #4597

Patch:
diff --git a/crates/ra_db/src/fixture.rs b/crates/ra_db/src/fixture.rs
index 482a2f3e65..f6b50c67cf 100644
--- a/crates/ra_db/src/fixture.rs
+++ b/crates/ra_db/src/fixture.rs
@@ -267,8 +267,8 @@ impl From<&FixtureMeta> for ParsedMeta {
                 ParsedMeta::Root { path: path.to_owned() }
             }
             FixtureMeta::File(f) => Self::File(FileMeta {
-                path: f.path.to_owned(),
-                krate: f.crate_name.to_owned(),
+                path: f.path.to_owned().into(),
+                krate: f.crate_name.to_owned().into(),
                 deps: f.deps.to_owned(),
                 cfg: f.cfg.to_owned(),
                 edition: f
diff --git a/crates/ra_hir_def/src/lang_item.rs b/crates/ra_hir_def/src/lang_item.rs
index 3516784b8d..d962db3cc7 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 {
         T: Into<AttrDefId> + Copy,
     {
         if let Some(lang_item_name) = lang_attr(db, item) {
-            self.items.entry(lang_item_name).or_insert_with(|| constructor(item));
+            self.items.entry(lang_item_name.clone()).or_insert_with(|| constructor(item));
         }
     }
 }
diff --git a/crates/ra_hir_ty/src/traits/builtin.rs b/crates/ra_hir_ty/src/traits/builtin.rs
index 88a422d2cb..ccab246bfa 100644
--- a/crates/ra_hir_ty/src/traits/builtin.rs
+++ b/crates/ra_hir_ty/src/traits/builtin.rs
@@ -290,7 +290,8 @@ fn trait_object_unsize_impl_datum(
     let self_trait_ref = TraitRef { trait_, substs: self_substs };
     let where_clauses = vec![GenericPredicate::Implemented(self_trait_ref)];
 
-    let impl_substs = Substs::builder(2).push(self_ty).push(Ty::Dyn(target_bounds.into())).build();
+    let impl_substs =
+        Substs::builder(2).push(self_ty).push(Ty::Dyn(target_bounds.clone().into())).build();
 
     let trait_ref = TraitRef { trait_: unsize_trait, substs: impl_substs };
 
diff --git a/crates/ra_ide/src/completion/complete_postfix.rs b/crates/ra_ide/src/completion/complete_postfix.rs
index 02e660ca8e..f2a52a407a 100644
--- a/crates/ra_ide/src/completion/complete_postfix.rs
+++ b/crates/ra_ide/src/completion/complete_postfix.rs
@@ -184,16 +184,6 @@ pub(super) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) {
         &format!("dbg!({})", receiver_text),
     )
     .add_to(acc);
-
-    postfix_snippet(
-        ctx,
-        cap,
-        &dot_receiver,
-        "call",
-        "function(expr)",
-        &format!("${{1}}({})", receiver_text),
-    )
-    .add_to(acc);
 }
 
 fn get_receiver_text(receiver: &ast::Expr, receiver_is_ambiguous_float_literal: bool) -> String {
@@ -265,13 +255,6 @@ mod tests {
                 insert: "Box::new(bar)",
                 detail: "Box::new(expr)",
             },
-            CompletionItem {
-                label: "call",
-                source_range: 89..89,
-                delete: 85..89,
-                insert: "${1}(bar)",
-                detail: "function(expr)",
-            },
             CompletionItem {
                 label: "dbg",
                 source_range: 89..89,
@@ -351,13 +334,6 @@ mod tests {
                 insert: "Box::new(bar)",
                 detail: "Box::new(expr)",
             },
-            CompletionItem {
-                label: "call",
-                source_range: 210..210,
-                delete: 206..210,
-                insert: "${1}(bar)",
-                detail: "function(expr)",
-            },
             CompletionItem {
                 label: "dbg",
                 source_range: 210..210,
@@ -437,13 +413,6 @@ mod tests {
                 insert: "Box::new(bar)",
                 detail: "Box::new(expr)",
             },
-            CompletionItem {
-                label: "call",
-                source_range: 211..211,
-                delete: 207..211,
-                insert: "${1}(bar)",
-                detail: "function(expr)",
-            },
             CompletionItem {
                 label: "dbg",
                 source_range: 211..211,
@@ -518,13 +487,6 @@ mod tests {
                 insert: "Box::new(bar)",
                 detail: "Box::new(expr)",
             },
-            CompletionItem {
-                label: "call",
-                source_range: 91..91,
-                delete: 87..91,
-                insert: "${1}(bar)",
-                detail: "function(expr)",
-            },
             CompletionItem {
                 label: "dbg",
                 source_range: 91..91,
@@ -584,13 +546,6 @@ mod tests {
                 insert: "Box::new(42)",
                 detail: "Box::new(expr)",
             },
-            CompletionItem {
-                label: "call",
-                source_range: 52..52,
-                delete: 49..52,
-                insert: "${1}(42)",
-                detail: "function(expr)",
-            },
             CompletionItem {
                 label: "dbg",
                 source_range: 52..52,
@@ -652,13 +607,6 @@ mod tests {
                 insert: "Box::new(bar)",
                 detail: "Box::new(expr)",
             },
-            CompletionItem {
-                label: "call",
-                source_range: 149..150,
-                delete: 145..150,
-                insert: "${1}(bar)",
-                detail: "function(expr)",
-            },
             CompletionItem {
                 label: "dbg",
                 source_range: 149..150,
@@ -718,13 +666,6 @@ mod tests {
                 insert: "Box::new(&&&&42)",
                 detail: "Box::new(expr)",
             },
-            CompletionItem {
-                label: "call",
-                source_range: 56..56,
-                delete: 49..56,
-                insert: "${1}(&&&&42)",
-                detail: "function(expr)",
-            },
             CompletionItem {
                 label: "dbg",
                 source_range: 56..56,
diff --git a/crates/ra_ide/src/display.rs b/crates/ra_ide/src/display.rs
index 827c094e71..8bb3121568 100644
--- a/crates/ra_ide/src/display.rs
+++ b/crates/ra_ide/src/display.rs
@@ -83,13 +83,12 @@ pub(crate) fn rust_code_markup_with_doc(
 
     if let Some(mod_path) = mod_path {
         if !mod_path.is_empty() {
-            format_to!(buf, "```rust\n{}\n```\n\n", mod_path);
+            format_to!(buf, "{}\n___\n\n", mod_path);
         }
     }
     format_to!(buf, "```rust\n{}\n```", code);
 
     if let Some(doc) = doc {
-        format_to!(buf, "\n___");
         format_to!(buf, "\n\n{}", doc);
     }
 
diff --git a/crates/ra_ide/src/hover.rs b/crates/ra_ide/src/hover.rs
index 3e721dcca3..1f4f6b8480 100644
--- a/crates/ra_ide/src/hover.rs
+++ b/crates/ra_ide/src/hover.rs
@@ -405,7 +405,7 @@ mod tests {
                 };
             }
         "#,
-            &["Foo\n```\n\n```rust\nfield_a: u32"],
+            &["Foo\n___\n\n```rust\nfield_a: u32"],
         );
 
         // Hovering over the field in the definition
@@ -422,7 +422,7 @@ mod tests {
                 };
             }
         "#,
-            &["Foo\n```\n\n```rust\nfield_a: u32"],
+            &["Foo\n___\n\n```rust\nfield_a: u32"],
         );
     }
 
@@ -475,7 +475,7 @@ fn main() {
             ",
         );
         let hover = analysis.hover(position).unwrap().unwrap();
-        assert_eq!(trim_markup_opt(hover.info.first()), Some("Option\n```\n\n```rust\nSome"));
+        assert_eq!(trim_markup_opt(hover.info.first()), Some("Option\n___\n\n```rust\nSome"));
 
         let (analysis, position) = single_file_with_position(
             "
@@ -503,12 +503,11 @@ fn main() {
         "#,
             &["
 Option
-```
+___
 
 ```rust
 None
 ```
-___
 
 The None variant
             "
@@ -528,12 +527,11 @@ The None variant
         "#,
             &["
 Option
-```
+___
 
 ```rust
 Some
 ```
-___
 
 The Some variant
             "
@@ -616,7 +614,7 @@ fn func(foo: i32) { if true { <|>foo; }; }
         let hover = analysis.hover(position).unwrap().unwrap();
         assert_eq!(
             trim_markup_opt(hover.info.first()),
-            Some("wrapper::Thing\n```\n\n```rust\nfn new() -> Thing")
+            Some("wrapper::Thing\n___\n\n```rust\nfn new() -> Thing")
         );
     }
 
@@ -893,7 +891,7 @@ fn func(foo: i32) { if true { <|>foo; }; }
                 fo<|>o();
             }
             ",
-            &["fn foo()\n```\n___\n\n<- `\u{3000}` here"],
+            &["fn foo()\n```\n\n<- `\u{3000}` here"],
         );
     }
 
diff --git a/crates/ra_ide/src/ssr.rs b/crates/ra_ide/src/ssr.rs
index 130d3b4c3b..1873d1d0d0 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 {
     ) -> Option<Match> {
         let match_ = check_opt_nodes(pattern.path(), code.path(), placeholders, match_)?;
 
-        let mut pattern_fields: Vec<RecordField> =
-            pattern.record_field_list().map(|x| x.fields().collect()).unwrap_or_default();
-        let mut code_fields: Vec<RecordField> =
-            code.record_field_list().map(|x| x.fields().collect()).unwrap_or_default();
+        let mut pattern_fields =
+            pattern.record_field_list().map(|x| x.fields().collect()).unwrap_or(vec![]);
+        let mut code_fields =
+            code.record_field_list().map(|x| x.fields().collect()).unwrap_or(vec![]);
 
         if pattern_fields.len() != code_fields.len() {
             return None;
diff --git a/editors/code/rust.tmGrammar.json b/editors/code/rust.tmGrammar.json
index cdcd557dc1..ab87cd39f6 100644
--- a/editors/code/rust.tmGrammar.json
+++ b/editors/code/rust.tmGrammar.json
@@ -207,7 +207,7 @@
 		{
 			"comment": "Miscellaneous operator",
 			"name": "keyword.operator.misc.rust",
-			"match": "(=>|::)"
+			"match": "(=>|::|\\?)"
 		},
 		{
 			"comment": "Comparison operator",


Test patch:
diff --git a/crates/rust-analyzer/tests/heavy_tests/main.rs b/crates/rust-analyzer/tests/heavy_tests/main.rs
index 405ddb3629..b1bfc968a8 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 {
     });
 
     let value = res.get("contents").unwrap().get("value").unwrap().to_string();
-    assert_eq!(value, r#""```rust\nfoo::Bar\n```\n\n```rust\nfn bar()\n```""#)
+    assert_eq!(value, r#""foo::Bar\n___\n\n```rust\nfn bar()\n```""#)
 }