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 | 55 |
1 files changed, 54 insertions, 1 deletions
diff --git a/crates/hir-expand/src/name.rs b/crates/hir-expand/src/name.rs index f1bf665707..6b48258f37 100644 --- a/crates/hir-expand/src/name.rs +++ b/crates/hir-expand/src/name.rs @@ -2,7 +2,7 @@ use std::fmt; -use syntax::{ast, SmolStr}; +use syntax::{ast, SmolStr, SyntaxKind}; /// `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 @@ -10,6 +10,10 @@ use syntax::{ast, SmolStr}; #[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] pub struct Name(Repr); +/// `EscapedName` will add a prefix "r#" to the wrapped `Name` when it is a raw identifier +#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] +pub struct EscapedName<'a>(&'a Name); + #[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] enum Repr { Text(SmolStr), @@ -25,6 +29,51 @@ impl fmt::Display for Name { } } +fn is_raw_identifier(name: &str) -> bool { + let is_keyword = SyntaxKind::from_keyword(name).is_some(); + is_keyword && !matches!(name, "self" | "crate" | "super" | "Self") +} + +impl<'a> fmt::Display for EscapedName<'a> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match &self.0 .0 { + Repr::Text(text) => { + if is_raw_identifier(text) { + write!(f, "r#{}", &text) + } else { + fmt::Display::fmt(&text, f) + } + } + Repr::TupleField(idx) => fmt::Display::fmt(&idx, f), + } + } +} + +impl<'a> EscapedName<'a> { + pub fn is_escaped(&self) -> bool { + match &self.0 .0 { + Repr::Text(it) => is_raw_identifier(&it), + Repr::TupleField(_) => false, + } + } + + /// Returns the textual representation of this name as a [`SmolStr`]. + /// Prefer using this over [`ToString::to_string`] if possible as this conversion is cheaper in + /// the general case. + pub fn to_smol_str(&self) -> SmolStr { + match &self.0 .0 { + Repr::Text(it) => { + if is_raw_identifier(&it) { + SmolStr::from_iter(["r#", &it]) + } else { + it.clone() + } + } + Repr::TupleField(it) => SmolStr::new(&it.to_string()), + } + } +} + impl Name { /// Note: this is private to make creating name from random string hard. /// Hopefully, this should allow us to integrate hygiene cleaner in the @@ -92,6 +141,10 @@ impl Name { Repr::TupleField(it) => SmolStr::new(&it.to_string()), } } + + pub fn escaped(&self) -> EscapedName { + EscapedName(self) + } } pub trait AsName { |