From 2b701e00f12e41ed2d9a75b6fd14fb20640d159d Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Sat, 26 Apr 2025 21:10:43 +0300 Subject: [PATCH 1/2] Escape raw names in labels properly --- .../rust-analyzer/crates/hir-expand/src/name.rs | 15 ++++++++++----- .../ide-completion/src/tests/expression.rs | 16 ++++++++++++++++ 2 files changed, 26 insertions(+), 5 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/name.rs b/src/tools/rust-analyzer/crates/hir-expand/src/name.rs index d43ef38f291d..37290edae4ec 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/name.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/name.rs @@ -191,7 +191,7 @@ impl Name { // FIXME: Remove this in favor of `display`, see fixme on `as_str` #[doc(hidden)] pub fn display_no_db(&self, edition: Edition) -> impl fmt::Display + '_ { - Display { name: self, needs_escaping: is_raw_identifier(self.symbol.as_str(), edition) } + Display { name: self, edition } } pub fn symbol(&self) -> &Symbol { @@ -201,15 +201,20 @@ impl Name { struct Display<'a> { name: &'a Name, - needs_escaping: bool, + edition: Edition, } impl fmt::Display for Display<'_> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - if self.needs_escaping { - write!(f, "r#")?; + let mut symbol = self.name.symbol.as_str(); + if let Some(s) = symbol.strip_prefix('\'') { + f.write_str("'")?; + symbol = s; } - fmt::Display::fmt(self.name.symbol.as_str(), f) + if is_raw_identifier(symbol, self.edition) { + f.write_str("r#")?; + } + f.write_str(symbol) } } diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs index b30ac43bf8fb..27d6bc7b14f2 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs @@ -2110,3 +2110,19 @@ fn foo() { "#]], ); } + +#[test] +fn escaped_label() { + check( + r#" +fn main() { + 'r#break: { + break '$0; + } +} + "#, + expect![[r#" + lb 'r#break + "#]], + ); +} From 8118676a08fa00ce5a8ffac6427c95c4df9a2e9b Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Sat, 26 Apr 2025 21:20:43 +0300 Subject: [PATCH 2/2] Don't escape `'static` As it is a valid lifetime without escaping. It does need to be escaped as a label, but we have no way to distinguish that. --- src/tools/rust-analyzer/crates/hir-expand/src/name.rs | 8 ++++++++ .../crates/ide-completion/src/completions/lifetime.rs | 4 ++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/name.rs b/src/tools/rust-analyzer/crates/hir-expand/src/name.rs index 37290edae4ec..217d991d110d 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/name.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/name.rs @@ -207,6 +207,14 @@ struct Display<'a> { impl fmt::Display for Display<'_> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let mut symbol = self.name.symbol.as_str(); + + if symbol == "'static" { + // FIXME: '`static` can also be a label, and there it does need escaping. + // But knowing where it is will require adding a parameter to `display()`, + // and that is an infectious change. + return f.write_str(symbol); + } + if let Some(s) = symbol.strip_prefix('\'') { f.write_str("'")?; symbol = s; diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/lifetime.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/lifetime.rs index b02f079b7213..8902cd09cec0 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/lifetime.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/lifetime.rs @@ -116,13 +116,13 @@ fn foo<'lifetime>(foo: &'a$0) {} check( r#" struct Foo; -impl<'impl> Foo { +impl<'r#impl> Foo { fn foo<'func>(&'a$0 self) {} } "#, expect![[r#" lt 'func - lt 'impl + lt 'r#impl lt 'static "#]], );