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

Issue:
Semantic Highlighting: Mutability of mut self is not always propagated
If the parameter is `fn(mut self, ...)` as opposed to `fn(&mut self, ...)` then the usage of self is not marked as mutable as it would for other variables.

Correct propagation on `&mut self`:

![https://i.imgur.com/FG5iBqS.png](https://i.imgur.com/FG5iBqS.png)

Incorrect propagation on `mut self`:

![https://i.imgur.com/M8PU72v.png](https://i.imgur.com/M8PU72v.png)


Pull request:
Fix `mut self` not emitting mutable binding on `self` use
Prior to this, when `self` in a function is taken by value and bound mutably, its use inside of the method body won't be marked `mutably`. 

Fixes #5461

Patch:
diff --git a/Cargo.toml b/Cargo.toml
index 87d33f06c8..218581d9d0 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -19,6 +19,18 @@ miniz_oxide.opt-level = 3
 incremental = true
 debug = 0 # Set this to 1 or 2 to get more useful backtraces in debugger.
 
+# Ideally, we would use `build-override` here, but some crates are also
+# needed at run-time and we end up compiling them twice.
+[profile.release.package]
+chalk-derive.opt-level = 0
+proc-macro2.opt-level = 0
+quote.opt-level = 0
+salsa-macros.opt-level = 0
+serde_derive.opt-level = 0
+syn.opt-level = 0
+tracing-attributes.opt-level = 0
+xtask.opt-level = 0
+
 [patch.'crates-io']
 # rowan = { path = "../rowan" }
 
diff --git a/crates/assists/src/handlers/fix_visibility.rs b/crates/assists/src/handlers/fix_visibility.rs
index d505e9444a..7cd76ea065 100644
--- a/crates/assists/src/handlers/fix_visibility.rs
+++ b/crates/assists/src/handlers/fix_visibility.rs
@@ -324,14 +324,14 @@ pub struct Foo { pub bar: () }
 
     #[test]
     fn fix_visibility_of_enum_variant_field() {
-        // Enum variants, as well as their fields, always get the enum's visibility. In fact, rustc
-        // rejects any visibility specifiers on them, so this assist should never fire on them.
-        check_assist_not_applicable(
+        check_assist(
             fix_visibility,
             r"mod foo { pub enum Foo { Bar { bar: () } } }
               fn main() { foo::Foo::Bar { <|>bar: () }; } ",
+            r"mod foo { pub enum Foo { Bar { $0pub(crate) bar: () } } }
+              fn main() { foo::Foo::Bar { bar: () }; } ",
         );
-        check_assist_not_applicable(
+        check_assist(
             fix_visibility,
             r"
 //- /lib.rs
@@ -339,6 +339,8 @@ mod foo;
 fn main() { foo::Foo::Bar { <|>bar: () }; }
 //- /foo.rs
 pub enum Foo { Bar { bar: () } }
+",
+            r"pub enum Foo { Bar { $0pub(crate) bar: () } }
 ",
         );
         check_assist_not_applicable(
diff --git a/crates/hir_def/src/adt.rs b/crates/hir_def/src/adt.rs
index 6539959c3c..d69ff2fc79 100644
--- a/crates/hir_def/src/adt.rs
+++ b/crates/hir_def/src/adt.rs
@@ -14,7 +14,7 @@ use tt::{Delimiter, DelimiterKind, Leaf, Subtree, TokenTree};
 use crate::{
     body::{CfgExpander, LowerCtx},
     db::DefDatabase,
-    item_tree::{AttrOwner, Field, Fields, ItemTree, ModItem, RawVisibilityId},
+    item_tree::{AttrOwner, Field, Fields, ItemTree, ModItem},
     src::HasChildSource,
     src::HasSource,
     trace::Trace,
@@ -91,7 +91,7 @@ impl StructData {
         let cfg_options = db.crate_graph()[loc.container.module(db).krate].cfg_options.clone();
 
         let strukt = &item_tree[loc.id.value];
-        let variant_data = lower_fields(&item_tree, &cfg_options, &strukt.fields, None);
+        let variant_data = lower_fields(&item_tree, &cfg_options, &strukt.fields);
         Arc::new(StructData {
             name: strukt.name.clone(),
             variant_data: Arc::new(variant_data),
@@ -105,7 +105,7 @@ impl StructData {
         let cfg_options = db.crate_graph()[loc.container.module(db).krate].cfg_options.clone();
 
         let union = &item_tree[loc.id.value];
-        let variant_data = lower_fields(&item_tree, &cfg_options, &union.fields, None);
+        let variant_data = lower_fields(&item_tree, &cfg_options, &union.fields);
 
         Arc::new(StructData {
             name: union.name.clone(),
@@ -126,8 +126,7 @@ impl EnumData {
         for var_id in enum_.variants.clone() {
             if item_tree.attrs(var_id.into()).is_cfg_enabled(&cfg_options) {
                 let var = &item_tree[var_id];
-                let var_data =
-                    lower_fields(&item_tree, &cfg_options, &var.fields, Some(enum_.visibility));
+                let var_data = lower_fields(&item_tree, &cfg_options, &var.fields);
 
                 variants.alloc(EnumVariantData {
                     name: var.name.clone(),
@@ -297,18 +296,13 @@ fn lower_struct(
     }
 }
 
-fn lower_fields(
-    item_tree: &ItemTree,
-    cfg_options: &CfgOptions,
-    fields: &Fields,
-    override_visibility: Option<RawVisibilityId>,
-) -> VariantData {
+fn lower_fields(item_tree: &ItemTree, cfg_options: &CfgOptions, fields: &Fields) -> VariantData {
     match fields {
         Fields::Record(flds) => {
             let mut arena = Arena::new();
             for field_id in flds.clone() {
                 if item_tree.attrs(field_id.into()).is_cfg_enabled(cfg_options) {
-                    arena.alloc(lower_field(item_tree, &item_tree[field_id], override_visibility));
+                    arena.alloc(lower_field(item_tree, &item_tree[field_id]));
                 }
             }
             VariantData::Record(arena)
@@ -317,7 +311,7 @@ fn lower_fields(
             let mut arena = Arena::new();
             for field_id in flds.clone() {
                 if item_tree.attrs(field_id.into()).is_cfg_enabled(cfg_options) {
-                    arena.alloc(lower_field(item_tree, &item_tree[field_id], override_visibility));
+                    arena.alloc(lower_field(item_tree, &item_tree[field_id]));
                 }
             }
             VariantData::Tuple(arena)
@@ -326,14 +320,10 @@ fn lower_fields(
     }
 }
 
-fn lower_field(
-    item_tree: &ItemTree,
-    field: &Field,
-    override_visibility: Option<RawVisibilityId>,
-) -> FieldData {
+fn lower_field(item_tree: &ItemTree, field: &Field) -> FieldData {
     FieldData {
         name: field.name.clone(),
         type_ref: field.type_ref.clone(),
-        visibility: item_tree[override_visibility.unwrap_or(field.visibility)].clone(),
+        visibility: item_tree[field.visibility].clone(),
     }
 }
diff --git a/crates/hir_def/src/body/lower.rs b/crates/hir_def/src/body/lower.rs
index 2d91bb21f5..01e72690a2 100644
--- a/crates/hir_def/src/body/lower.rs
+++ b/crates/hir_def/src/body/lower.rs
@@ -107,7 +107,10 @@ impl ExprCollector<'_> {
                 let param_pat = self.alloc_pat(
                     Pat::Bind {
                         name: name![self],
-                        mode: BindingAnnotation::Unannotated,
+                        mode: BindingAnnotation::new(
+                            self_param.mut_token().is_some() && self_param.amp_token().is_none(),
+                            false,
+                        ),
                         subpat: None,
                     },
                     Either::Right(ptr),
diff --git a/crates/ide/src/completion/complete_postfix/format_like.rs b/crates/ide/src/completion/complete_postfix/format_like.rs
index 50d1e5c815..81c33bf3af 100644
--- a/crates/ide/src/completion/complete_postfix/format_like.rs
+++ b/crates/ide/src/completion/complete_postfix/format_like.rs
@@ -25,7 +25,6 @@ static KINDS: &[(&str, &str)] = &[
     ("fmt", "format!"),
     ("panic", "panic!"),
     ("println", "println!"),
-    ("eprintln", "eprintln!"),
     ("logd", "log::debug!"),
     ("logt", "log::trace!"),
     ("logi", "log::info!"),
@@ -260,7 +259,6 @@ mod tests {
     fn test_into_suggestion() {
         let test_vector = &[
             ("println!", "{}", r#"println!("{}", $1)"#),
-            ("eprintln!", "{}", r#"eprintln!("{}", $1)"#),
             (
                 "log::info!",
                 "{} {expr} {} {2 + 2}",
diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs
index d54c06b14f..57f3581b6b 100644
--- a/crates/ide/src/lib.rs
+++ b/crates/ide/src/lib.rs
@@ -77,9 +77,7 @@ pub use crate::{
     hover::{HoverAction, HoverConfig, HoverGotoTypeData, HoverResult},
     inlay_hints::{InlayHint, InlayHintsConfig, InlayKind},
     markup::Markup,
-    references::{
-        Declaration, Reference, ReferenceAccess, ReferenceKind, ReferenceSearchResult, RenameError,
-    },
+    references::{Declaration, Reference, ReferenceAccess, ReferenceKind, ReferenceSearchResult},
     runnables::{Runnable, RunnableKind, TestId},
     syntax_highlighting::{
         Highlight, HighlightModifier, HighlightModifiers, HighlightTag, HighlightedRange,
@@ -492,7 +490,7 @@ impl Analysis {
         &self,
         position: FilePosition,
         new_name: &str,
-    ) -> Cancelable<Result<RangeInfo<SourceChange>, RenameError>> {
+    ) -> Cancelable<Option<RangeInfo<SourceChange>>> {
         self.with_db(|db| references::rename(db, position, new_name))
     }
 
diff --git a/crates/ide/src/references.rs b/crates/ide/src/references.rs
index f65a05ea33..571dd5452c 100644
--- a/crates/ide/src/references.rs
+++ b/crates/ide/src/references.rs
@@ -26,7 +26,6 @@ use syntax::{
 use crate::{display::TryToNav, FilePosition, FileRange, NavigationTarget, RangeInfo};
 
 pub(crate) use self::rename::rename;
-pub use self::rename::RenameError;
 
 pub use ide_db::search::{Reference, ReferenceAccess, ReferenceKind};
 
@@ -733,30 +732,6 @@ fn f(e: En) {
         );
     }
 
-    #[test]
-    fn test_find_all_refs_enum_var_privacy() {
-        check(
-            r#"
-mod m {
-    pub enum En {
-        Variant {
-            field<|>: u8,
-        }
-    }
-}
-
-fn f() -> m::En {
-    m::En::Variant { field: 0 }
-}
-"#,
-            expect![[r#"
-                field RECORD_FIELD FileId(0) 56..65 56..61 Other
-
-                FileId(0) 125..130 Other Read
-            "#]],
-        );
-    }
-
     fn check(ra_fixture: &str, expect: Expect) {
         check_with_scope(ra_fixture, None, expect)
     }
diff --git a/crates/ide/src/references/rename.rs b/crates/ide/src/references/rename.rs
index f3b5cfc8c1..8cbe1ae5a2 100644
--- a/crates/ide/src/references/rename.rs
+++ b/crates/ide/src/references/rename.rs
@@ -6,16 +6,11 @@ use ide_db::{
     defs::{classify_name, classify_name_ref, Definition, NameClass, NameRefClass},
     RootDatabase,
 };
-
-use std::{
-    convert::TryInto,
-    error::Error,
-    fmt::{self, Display},
-};
+use std::convert::TryInto;
 use syntax::{
     algo::find_node_at_offset,
     ast::{self, NameOwner},
-    lex_single_syntax_kind, match_ast, AstNode, SyntaxKind, SyntaxNode, SyntaxToken,
+    lex_single_valid_syntax_kind, match_ast, AstNode, SyntaxKind, SyntaxNode, SyntaxToken,
 };
 use test_utils::mark;
 use text_edit::TextEdit;
@@ -25,37 +20,17 @@ use crate::{
     SourceChange, SourceFileEdit, TextRange, TextSize,
 };
 
-#[derive(Debug)]
-pub struct RenameError(pub(crate) String);
-
-impl fmt::Display for RenameError {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        Display::fmt(&self.0, f)
-    }
-}
-
-impl Error for RenameError {}
-
 pub(crate) fn rename(
     db: &RootDatabase,
     position: FilePosition,
     new_name: &str,
-) -> Result<RangeInfo<SourceChange>, RenameError> {
+) -> Option<RangeInfo<SourceChange>> {
     let sema = Semantics::new(db);
 
-    match lex_single_syntax_kind(new_name) {
-        Some(res) => match res {
-            (SyntaxKind::IDENT, _) => (),
-            (SyntaxKind::UNDERSCORE, _) => (),
-            (SyntaxKind::SELF_KW, _) => return rename_to_self(&sema, position),
-            (_, Some(syntax_error)) => {
-                return Err(RenameError(format!("Invalid name `{}`: {}", new_name, syntax_error)))
-            }
-            (_, None) => {
-                return Err(RenameError(format!("Invalid name `{}`: not an identifier", new_name)))
-            }
-        },
-        None => return Err(RenameError(format!("Invalid name `{}`: not an identifier", new_name))),
+    match lex_single_valid_syntax_kind(new_name)? {
+        SyntaxKind::IDENT | SyntaxKind::UNDERSCORE => (),
+        SyntaxKind::SELF_KW => return rename_to_self(&sema, position),
+        _ => return None,
     }
 
     let source_file = sema.parse(position.file_id);
@@ -128,7 +103,7 @@ fn rename_mod(
     position: FilePosition,
     module: Module,
     new_name: &str,
-) -> Result<RangeInfo<SourceChange>, RenameError> {
+) -> Option<RangeInfo<SourceChange>> {
     let mut source_file_edits = Vec::new();
     let mut file_system_edits = Vec::new();
 
@@ -150,7 +125,7 @@ fn rename_mod(
 
     if let Some(src) = module.declaration_source(sema.db) {
         let file_id = src.file_id.original_file(sema.db);
-        let name = src.value.name().unwrap();
+        let name = src.value.name()?;
         let edit = SourceFileEdit {
             file_id,
             edit: TextEdit::replace(name.syntax().text_range(), new_name.into()),
@@ -158,40 +133,35 @@ fn rename_mod(
         source_file_edits.push(edit);
     }
 
-    let RangeInfo { range, info: refs } = find_all_refs(sema, position, None)
-        .ok_or_else(|| RenameError("No references found at position".to_string()))?;
+    let RangeInfo { range, info: refs } = find_all_refs(sema, position, None)?;
     let ref_edits = refs
         .references
         .into_iter()
         .map(|reference| source_edit_from_reference(reference, new_name));
     source_file_edits.extend(ref_edits);
 
-    Ok(RangeInfo::new(range, SourceChange::from_edits(source_file_edits, file_system_edits)))
+    Some(RangeInfo::new(range, SourceChange::from_edits(source_file_edits, file_system_edits)))
 }
 
 fn rename_to_self(
     sema: &Semantics<RootDatabase>,
     position: FilePosition,
-) -> Result<RangeInfo<SourceChange>, RenameError> {
+) -> Option<RangeInfo<SourceChange>> {
     let source_file = sema.parse(position.file_id);
     let syn = source_file.syntax();
 
-    let fn_def = find_node_at_offset::<ast::Fn>(syn, position.offset)
-        .ok_or_else(|| RenameError("No surrounding method declaration found".to_string()))?;
-    let params =
-        fn_def.param_list().ok_or_else(|| RenameError("Method has no parameters".to_string()))?;
+    let fn_def = find_node_at_offset::<ast::Fn>(syn, position.offset)?;
+    let params = fn_def.param_list()?;
     if params.self_param().is_some() {
-        return Err(RenameError("Method already has a self parameter".to_string()));
+        return None; // method already has self param
     }
-    let first_param =
-        params.params().next().ok_or_else(|| RenameError("Method has no parameters".into()))?;
+    let first_param = params.params().next()?;
     let mutable = match first_param.ty() {
         Some(ast::Type::RefType(rt)) => rt.mut_token().is_some(),
-        _ => return Err(RenameError("Not renaming other types".to_string())),
+        _ => return None, // not renaming other types
     };
 
-    let RangeInfo { range, info: refs } = find_all_refs(sema, position, None)
-        .ok_or_else(|| RenameError("No reference found at position".to_string()))?;
+    let RangeInfo { range, info: refs } = find_all_refs(sema, position, None)?;
 
     let param_range = first_param.syntax().text_range();
     let (param_ref, usages): (Vec<Reference>, Vec<Reference>) = refs
@@ -199,7 +169,7 @@ fn rename_to_self(
         .partition(|reference| param_range.intersect(reference.file_range.range).is_some());
 
     if param_ref.is_empty() {
-        return Err(RenameError("Parameter to rename not found".to_string()));
+        return None;
     }
 
     let mut edits = usages
@@ -215,7 +185,7 @@ fn rename_to_self(
         ),
     });
 
-    Ok(RangeInfo::new(range, SourceChange::from(edits)))
+    Some(RangeInfo::new(range, SourceChange::from(edits)))
 }
 
 fn text_edit_from_self_param(
@@ -246,13 +216,12 @@ fn rename_self_to_param(
     position: FilePosition,
     self_token: SyntaxToken,
     new_name: &str,
-) -> Result<RangeInfo<SourceChange>, RenameError> {
+) -> Option<RangeInfo<SourceChange>> {
     let source_file = sema.parse(position.file_id);
     let syn = source_file.syntax();
 
     let text = sema.db.file_text(position.file_id);
-    let fn_def = find_node_at_offset::<ast::Fn>(syn, position.offset)
-        .ok_or_else(|| RenameError("No surrounding method declaration found".to_string()))?;
+    let fn_def = find_node_at_offset::<ast::Fn>(syn, position.offset)?;
     let search_range = fn_def.syntax().text_range();
 
     let mut edits: Vec<SourceFileEdit> = vec![];
@@ -266,8 +235,7 @@ fn rename_self_to_param(
             syn.token_at_offset(offset).find(|t| t.kind() == SyntaxKind::SELF_KW)
         {
             let edit = if let Some(ref self_param) = ast::SelfParam::cast(usage.parent()) {
-                text_edit_from_self_param(syn, self_param, new_name)
-                    .ok_or_else(|| RenameError("No target type found".to_string()))?
+                text_edit_from_self_param(syn, self_param, new_name)?
             } else {
                 TextEdit::replace(usage.text_range(), String::from(new_name))
             };
@@ -278,18 +246,15 @@ fn rename_self_to_param(
     let range = ast::SelfParam::cast(self_token.parent())
         .map_or(self_token.text_range(), |p| p.syntax().text_range());
 
-    Ok(RangeInfo::new(range, SourceChange::from(edits)))
+    Some(RangeInfo::new(range, SourceChange::from(edits)))
 }
 
 fn rename_reference(
     sema: &Semantics<RootDatabase>,
     position: FilePosition,
     new_name: &str,
-) -> Result<RangeInfo<SourceChange>, RenameError> {
-    let RangeInfo { range, info: refs } = match find_all_refs(sema, position, None) {
-        Some(range_info) => range_info,
-        None => return Err(RenameError("No references found at position".to_string())),
-    };
+) -> Option<RangeInfo<SourceChange>> {
+    let RangeInfo { range, info: refs } = find_all_refs(sema, position, None)?;
 
     let edit = refs
         .into_iter()
@@ -297,10 +262,10 @@ fn rename_reference(
         .collect::<Vec<_>>();
 
     if edit.is_empty() {
-        return Err(RenameError("No references found at position".to_string()));
+        return None;
     }
 
-    Ok(RangeInfo::new(range, SourceChange::from(edit)))
+    Some(RangeInfo::new(range, SourceChange::from(edit)))
 }
 
 #[cfg(test)]
@@ -315,45 +280,25 @@ mod tests {
     fn check(new_name: &str, ra_fixture_before: &str, ra_fixture_after: &str) {
         let ra_fixture_after = &trim_indent(ra_fixture_after);
         let (analysis, position) = fixture::position(ra_fixture_before);
-        let rename_result = analysis
-            .rename(position, new_name)
-            .unwrap_or_else(|err| panic!("Rename to '{}' was cancelled: {}", new_name, err));
-        match rename_result {
-            Ok(source_change) => {
-                let mut text_edit_builder = TextEdit::builder();
-                let mut file_id: Option<FileId> = None;
-                for edit in source_change.info.source_file_edits {
-                    file_id = Some(edit.file_id);
-                    for indel in edit.edit.into_iter() {
-                        text_edit_builder.replace(indel.delete, indel.insert);
-                    }
-                }
-                let mut result = analysis.file_text(file_id.unwrap()).unwrap().to_string();
-                text_edit_builder.finish().apply(&mut result);
-                assert_eq_text!(ra_fixture_after, &*result);
-            }
-            Err(err) => {
-                if ra_fixture_after.starts_with("error:") {
-                    let error_message = ra_fixture_after
-                        .chars()
-                        .into_iter()
-                        .skip("error:".len())
-                        .collect::<String>();
-                    assert_eq!(error_message.trim(), err.to_string());
-                    return;
-                } else {
-                    panic!("Rename to '{}' failed unexpectedly: {}", new_name, err)
+        let source_change = analysis.rename(position, new_name).unwrap();
+        let mut text_edit_builder = TextEdit::builder();
+        let mut file_id: Option<FileId> = None;
+        if let Some(change) = source_change {
+            for edit in change.info.source_file_edits {
+                file_id = Some(edit.file_id);
+                for indel in edit.edit.into_iter() {
+                    text_edit_builder.replace(indel.delete, indel.insert);
                 }
             }
-        };
+        }
+        let mut result = analysis.file_text(file_id.unwrap()).unwrap().to_string();
+        text_edit_builder.finish().apply(&mut result);
+        assert_eq_text!(ra_fixture_after, &*result);
     }
 
     fn check_expect(new_name: &str, ra_fixture: &str, expect: Expect) {
         let (analysis, position) = fixture::position(ra_fixture);
-        let source_change = analysis
-            .rename(position, new_name)
-            .unwrap()
-            .expect("Expect returned RangeInfo to be Some, but was None");
+        let source_change = analysis.rename(position, new_name).unwrap().unwrap();
         expect.assert_debug_eq(&source_change)
     }
 
@@ -368,30 +313,11 @@ mod tests {
     }
 
     #[test]
-    fn test_rename_to_invalid_identifier1() {
-        check(
-            "invalid!",
-            r#"fn main() { let i<|> = 1; }"#,
-            "error: Invalid name `invalid!`: not an identifier",
-        );
-    }
-
-    #[test]
-    fn test_rename_to_invalid_identifier2() {
-        check(
-            "multiple tokens",
-            r#"fn main() { let i<|> = 1; }"#,
-            "error: Invalid name `multiple tokens`: not an identifier",
-        );
-    }
-
-    #[test]
-    fn test_rename_to_invalid_identifier3() {
-        check(
-            "let",
-            r#"fn main() { let i<|> = 1; }"#,
-            "error: Invalid name `let`: not an identifier",
-        );
+    fn test_rename_to_invalid_identifier() {
+        let (analysis, position) = fixture::position(r#"fn main() { let i<|> = 1; }"#);
+        let new_name = "invalid!";
+        let source_change = analysis.rename(position, new_name).unwrap();
+        assert!(source_change.is_none());
     }
 
     #[test]
@@ -423,15 +349,6 @@ fn main() {
         );
     }
 
-    #[test]
-    fn test_rename_unresolved_reference() {
-        check(
-            "new_name",
-            r#"fn main() { let _ = unresolved_ref<|>; }"#,
-            "error: No references found at position",
-        );
-    }
-
     #[test]
     fn test_rename_for_macro_args() {
         check(
diff --git a/crates/rust-analyzer/src/handlers.rs b/crates/rust-analyzer/src/handlers.rs
index 4e3340b0dd..468655f9c3 100644
--- a/crates/rust-analyzer/src/handlers.rs
+++ b/crates/rust-analyzer/src/handlers.rs
@@ -646,9 +646,14 @@ pub(crate) fn handle_prepare_rename(
     let _p = profile::span("handle_prepare_rename");
     let position = from_proto::file_position(&snap, params)?;
 
-    let change = snap.analysis.rename(position, "dummy")??;
+    let optional_change = snap.analysis.rename(position, "dummy")?;
+    let range = match optional_change {
+        None => return Ok(None),
+        Some(it) => it.range,
+    };
+
     let line_index = snap.analysis.file_line_index(position.file_id)?;
-    let range = to_proto::range(&line_index, change.range);
+    let range = to_proto::range(&line_index, range);
     Ok(Some(PrepareRenameResponse::Range(range)))
 }
 
@@ -667,8 +672,12 @@ pub(crate) fn handle_rename(
         .into());
     }
 
-    let change = snap.analysis.rename(position, &*params.new_name)??;
-    let workspace_edit = to_proto::workspace_edit(&snap, change.info)?;
+    let optional_change = snap.analysis.rename(position, &*params.new_name)?;
+    let source_change = match optional_change {
+        None => return Ok(None),
+        Some(it) => it.info,
+    };
+    let workspace_edit = to_proto::workspace_edit(&snap, source_change)?;
     Ok(Some(workspace_edit))
 }
 


Test patch:
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlighting.html b/crates/ide/src/syntax_highlighting/test_data/highlighting.html
index 1d8a3c4046..3d54e48244 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
 
 <span class="keyword">impl</span> <span class="struct">Foo</span> <span class="punctuation">{</span>
     <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>
-        <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>
+        <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>
     <span class="punctuation">}</span>
 
     <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>