{"record":{"id":"be23892ae4e88391","repo":"rust-lang/rust-analyzer","slug":"can-t-rename-local-that-is-defined-in-a-macro-decl","errorCode":null,"errorMessage":"Can't rename local that is defined in a macro declaration","messagePattern":"Can't rename local that is defined in a macro declaration","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/ide-db/src/rename.rs","lineNumber":725,"sourceCode":"                        .and_then(|x| x.name())\n                        .and_then(|x| sema.original_range_opt(x.syntax()))\n                        .or_else(|| {\n                            source\n                                .source\n                                .syntax()\n                                .original_file_range_opt(sema.db)\n                                .map(TupleExt::head)\n                        }) {\n                        Some(FileRange { file_id: file_id2, range }) => {\n                            file_id = Some(file_id2);\n                            edit.replace(\n                                range,\n                                new_name.display(sema.db, file_id2.edition(sema.db)).to_string(),\n                            );\n                            continue;\n                        }\n                        None => {\n                            bail!(\"Can't rename local that is defined in a macro declaration\")\n                        }\n                    }\n                }\n            };\n            file_id = Some(source.file_id);\n            if let Either::Left(pat) = source.value {\n                let name_range = pat.name().unwrap().syntax().text_range();\n\n                // special cases required for renaming fields/locals in Record patterns\n                if let Some(pat_field) = pat.syntax().parent().and_then(ast::RecordPatField::cast) {\n                    if let Some(name_ref) = pat_field.name_ref() {\n                        if new_name.as_str() == name_ref.text().trim_start_matches(\"r#\")\n                            && pat.at_token().is_none()\n                        {\n                            // Foo { field: ref mut local } -> Foo { ref mut field }\n                            //       ^^^^^^ delete this\n                            //                      ^^^^^ replace this with `field`\n                            cov_mark::hit!(test_rename_local_put_init_shorthand_pat);","sourceCodeStart":707,"sourceCodeEnd":743,"githubUrl":"https://github.com/rust-lang/rust-analyzer/blob/e8f7e90aa3e7b26aa9a000200f606c1078da99ec/crates/ide-db/src/rename.rs#L707-L743","documentation":"In `source_edit_from_def`, rust_analyzer must find the textual source of the definition being renamed to place the edit. When the local is declared inside a macro (the pattern comes from macro expansion and has no mappable original syntax node), no source range exists and it bails with \"Can't rename local that is defined in a macro declaration\".","triggerScenarios":"Renaming a `Definition::Local` whose binding pattern was produced by a macro expansion — e.g. a variable introduced by `macro_rules!` or `vec![]` destructuring — such that `source.value` pattern resolution returns `None` at crates/ide-db/src/rename.rs:725.","commonSituations":"User places the cursor on a variable generated by a macro (`let (a, b) = tuple;` from a macro, or identifiers emitted by declarative macros) and invokes rename; the IDE cannot produce text edits inside macro input.","solutions":["Rename the local at its real (non-macro) definition site, or inline the macro expansion and rename there.","Restructure the code so the variable is bound outside the macro.","In tooling, detect that the definition's source is inside a macro file and disable the rename action upfront."],"exampleFix":"// before\nmacro_rules! m { ($v:ident) => { let x = 1; let _ = $v; } }\n// renaming `x` (declared inside the macro) fails\n// after: declare the local outside the macro\nlet x = 1;\nmacro_rules! m { ($v:ident) => { let _ = $v + x; } }\nrename(x_local, \"y\")?; // ok","handlingStrategy":"try-catch","validationCode":"fn is_in_macro_file(def: &Definition, sema: &Semantics<'_, RootDatabase>) -> bool {\n    def.source(sema)\n        .map(|s| s.file_id.is_macro())\n        .unwrap_or(true)\n}","typeGuard":"fn has_real_source(def: &Definition, sema: &Semantics<'_, RootDatabase>) -> bool {\n    def.source(sema).map(|s| !s.file_id.is_macro()).unwrap_or(false)\n}","tryCatchPattern":"match def.rename(sema, new_name, ...) {\n    Err(e) if e.to_string().contains(\"defined in a macro declaration\") => eprintln!(\"expand the macro and rename there\"),\n    other => other?,\n}","preventionTips":["Disable rename actions when the definition's source maps into a macro expansion file.","Bind variables outside macros when their names need to change.","Fall back to textual find/replace in the macro definition for such locals."],"tags":["rust","ide","rename","macros"],"backgroundTag":"rename-target-in-macro-expansion","analyzedSha":"e8f7e90aa3e7b26aa9a000200f606c1078da99ec","analyzedAt":"2026-09-03T21:08:06.959Z","contentChangedAt":"2026-09-03T21:08:06.959Z","schemaVersion":2},"datasetVersion":"2026-09-11T07:07:21.782Z"}