complete raw identifier with "r#" prefix

This commit is contained in:
Hongxu Xu 2022-06-26 14:45:30 +08:00
parent 5bb123d970
commit f536766efb
12 changed files with 304 additions and 60 deletions

View file

@ -20,6 +20,9 @@ pub struct ModPath {
segments: Vec<Name>,
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct EscapedModPath<'a>(&'a ModPath);
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum PathKind {
Plain,
@ -97,10 +100,12 @@ impl ModPath {
_ => None,
}
}
}
impl Display for ModPath {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
pub fn escaped(&self) -> EscapedModPath {
EscapedModPath(self)
}
fn _fmt(&self, f: &mut fmt::Formatter<'_>, escaped: bool) -> fmt::Result {
let mut first_segment = true;
let mut add_segment = |s| -> fmt::Result {
if !first_segment {
@ -127,12 +132,28 @@ impl Display for ModPath {
f.write_str("::")?;
}
first_segment = false;
segment.fmt(f)?;
if escaped {
segment.escaped().fmt(f)?
} else {
segment.fmt(f)?
};
}
Ok(())
}
}
impl Display for ModPath {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self._fmt(f, false)
}
}
impl<'a> Display for EscapedModPath<'a> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.0._fmt(f, true)
}
}
impl From<Name> for ModPath {
fn from(name: Name) -> ModPath {
ModPath::from_segments(PathKind::Plain, iter::once(name))

View file

@ -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 {