Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir-expand/src/name.rs')
| -rw-r--r-- | crates/hir-expand/src/name.rs | 90 |
1 files changed, 37 insertions, 53 deletions
diff --git a/crates/hir-expand/src/name.rs b/crates/hir-expand/src/name.rs index d012d272d7..54313904a7 100644 --- a/crates/hir-expand/src/name.rs +++ b/crates/hir-expand/src/name.rs @@ -3,22 +3,22 @@ use std::fmt; use intern::{sym, Symbol}; -use span::SyntaxContextId; -use syntax::{ast, utils::is_raw_identifier}; +use span::{Edition, SyntaxContextId}; +use syntax::ast; +use syntax::utils::is_raw_identifier; /// `Name` is a wrapper around string, which is used in hir for both references /// and declarations. In theory, names should also carry hygiene info, but we are /// not there yet! /// -/// Note that `Name` holds and prints escaped name i.e. prefixed with "r#" when it -/// is a raw identifier. Use [`unescaped()`][Name::unescaped] when you need the -/// name without "r#". +/// Note that the rawness (`r#`) of names does not depend on whether they are written raw. +/// This is because we want to show (in completions etc.) names as raw depending on the needs +/// of the current crate, for example if it is edition 2021 complete `gen` even if the defining +/// crate is in edition 2024 and wrote `r#gen`, and the opposite holds as well. #[derive(Clone, PartialEq, Eq, Hash)] pub struct Name { symbol: Symbol, ctx: (), - // FIXME: We should probably encode rawness as a property here instead, once we have hygiene - // in here we've got 4 bytes of padding to fill anyways } impl fmt::Debug for Name { @@ -42,6 +42,7 @@ impl PartialOrd for Name { } } +// No need to strip `r#`, all comparisons are done against well-known symbols. impl PartialEq<Symbol> for Name { fn eq(&self, sym: &Symbol) -> bool { self.symbol == *sym @@ -55,16 +56,16 @@ impl PartialEq<Name> for Symbol { } /// Wrapper of `Name` to print the name without "r#" even when it is a raw identifier. -#[derive(Debug, Clone, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct UnescapedName<'a>(&'a Name); -impl UnescapedName<'_> { - pub fn display(&self, db: &dyn crate::db::ExpandDatabase) -> impl fmt::Display + '_ { +impl<'a> UnescapedName<'a> { + pub fn display(self, db: &dyn crate::db::ExpandDatabase) -> impl fmt::Display + 'a { _ = db; UnescapedDisplay { name: self } } #[doc(hidden)] - pub fn display_no_db(&self) -> impl fmt::Display + '_ { + pub fn display_no_db(self) -> impl fmt::Display + 'a { UnescapedDisplay { name: self } } } @@ -77,16 +78,9 @@ impl Name { Name { symbol: Symbol::intern(text), ctx: () } } - pub fn new(text: &str, raw: tt::IdentIsRaw, ctx: SyntaxContextId) -> Name { + pub fn new(text: &str, ctx: SyntaxContextId) -> Name { _ = ctx; - Name { - symbol: if raw.yes() { - Symbol::intern(&format!("{}{text}", raw.as_str())) - } else { - Symbol::intern(text) - }, - ctx: (), - } + Self::new_text(text) } pub fn new_tuple_field(idx: usize) -> Name { @@ -97,23 +91,9 @@ impl Name { Name { symbol: Symbol::intern(lt.text().as_str()), ctx: () } } - /// Shortcut to create a name from a string literal. - fn new_ref(text: &str) -> Name { - Name { symbol: Symbol::intern(text), ctx: () } - } - /// Resolve a name from the text of token. fn resolve(raw_text: &str) -> Name { - match raw_text.strip_prefix("r#") { - // When `raw_text` starts with "r#" but the name does not coincide with any - // keyword, we never need the prefix so we strip it. - Some(text) if !is_raw_identifier(text) => Name::new_ref(text), - // Keywords (in the current edition) *can* be used as a name in earlier editions of - // Rust, e.g. "try" in Rust 2015. Even in such cases, we keep track of them in their - // escaped form. - None if is_raw_identifier(raw_text) => Name::new_text(&format!("r#{}", raw_text)), - _ => Name::new_text(raw_text), - } + Name::new_text(raw_text.trim_start_matches("r#")) } /// A fake name for things missing in the source code. @@ -159,19 +139,23 @@ impl Name { UnescapedName(self) } - pub fn is_escaped(&self) -> bool { - self.symbol.as_str().starts_with("r#") + pub fn is_escaped(&self, edition: Edition) -> bool { + is_raw_identifier(self.symbol.as_str(), edition) } - pub fn display<'a>(&'a self, db: &dyn crate::db::ExpandDatabase) -> impl fmt::Display + 'a { + pub fn display<'a>( + &'a self, + db: &dyn crate::db::ExpandDatabase, + edition: Edition, + ) -> impl fmt::Display + 'a { _ = db; - Display { name: self } + self.display_no_db(edition) } // FIXME: Remove this #[doc(hidden)] - pub fn display_no_db(&self) -> impl fmt::Display + '_ { - Display { name: self } + pub fn display_no_db(&self, edition: Edition) -> impl fmt::Display + '_ { + Display { name: self, needs_escaping: is_raw_identifier(self.symbol.as_str(), edition) } } pub fn symbol(&self) -> &Symbol { @@ -183,39 +167,39 @@ impl Name { Self { symbol, ctx: () } } - pub fn new_symbol_maybe_raw(sym: Symbol, raw: tt::IdentIsRaw, ctx: SyntaxContextId) -> Self { - if raw.no() { - Self { symbol: sym, ctx: () } - } else { - Name::new(sym.as_str(), raw, ctx) - } - } - // FIXME: This needs to go once we have hygiene pub const fn new_symbol_root(sym: Symbol) -> Self { Self { symbol: sym, ctx: () } } + + #[inline] + pub fn eq_ident(&self, ident: &str) -> bool { + self.as_str() == ident.trim_start_matches("r#") + } } struct Display<'a> { name: &'a Name, + needs_escaping: bool, } impl fmt::Display for Display<'_> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + if self.needs_escaping { + write!(f, "r#")?; + } fmt::Display::fmt(self.name.symbol.as_str(), f) } } struct UnescapedDisplay<'a> { - name: &'a UnescapedName<'a>, + name: UnescapedName<'a>, } impl fmt::Display for UnescapedDisplay<'_> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let symbol = &self.name.0.symbol.as_str(); - let text = symbol.strip_prefix("r#").unwrap_or(symbol); - fmt::Display::fmt(&text, f) + let symbol = self.name.0.symbol.as_str(); + fmt::Display::fmt(symbol, f) } } |