@@ -7,13 +7,21 @@ use syntax::{ast, SmolStr, SyntaxKind};
7
7
/// `Name` is a wrapper around string, which is used in hir for both references
8
8
/// and declarations. In theory, names should also carry hygiene info, but we are
9
9
/// not there yet!
10
+ ///
11
+ /// Note that `Name` holds and prints escaped name i.e. prefixed with "r#" when it
12
+ /// is a raw identifier. Use [`unescaped()`][Name::unescaped] when you need the
13
+ /// name without "r#".
10
14
#[ derive( Debug , Clone , PartialEq , Eq , Hash , PartialOrd , Ord ) ]
11
15
pub struct Name ( Repr ) ;
12
16
13
17
/// `EscapedName` will add a prefix "r#" to the wrapped `Name` when it is a raw identifier
14
18
#[ derive( Debug , Clone , PartialEq , Eq , Hash , PartialOrd , Ord ) ]
15
19
pub struct EscapedName < ' a > ( & ' a Name ) ;
16
20
21
+ /// Wrapper of `Name` to print the name without "r#" even when it is a raw identifier.
22
+ #[ derive( Debug , Clone , PartialEq , Eq , Hash , PartialOrd , Ord ) ]
23
+ pub struct UnescapedName < ' a > ( & ' a Name ) ;
24
+
17
25
#[ derive( Debug , Clone , PartialEq , Eq , Hash , PartialOrd , Ord ) ]
18
26
enum Repr {
19
27
Text ( SmolStr ) ,
@@ -49,6 +57,35 @@ impl<'a> fmt::Display for EscapedName<'a> {
49
57
}
50
58
}
51
59
60
+ impl < ' a > fmt:: Display for UnescapedName < ' a > {
61
+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
62
+ match & self . 0 . 0 {
63
+ Repr :: Text ( text) => {
64
+ let text = text. strip_prefix ( "r#" ) . unwrap_or ( text) ;
65
+ fmt:: Display :: fmt ( & text, f)
66
+ }
67
+ Repr :: TupleField ( idx) => fmt:: Display :: fmt ( & idx, f) ,
68
+ }
69
+ }
70
+ }
71
+
72
+ impl < ' a > UnescapedName < ' a > {
73
+ /// Returns the textual representation of this name as a [`SmolStr`]. Prefer using this over
74
+ /// [`ToString::to_string`] if possible as this conversion is cheaper in the general case.
75
+ pub fn to_smol_str ( & self ) -> SmolStr {
76
+ match & self . 0 . 0 {
77
+ Repr :: Text ( it) => {
78
+ if let Some ( stripped) = it. strip_prefix ( "r#" ) {
79
+ SmolStr :: new ( stripped)
80
+ } else {
81
+ it. clone ( )
82
+ }
83
+ }
84
+ Repr :: TupleField ( it) => SmolStr :: new ( & it. to_string ( ) ) ,
85
+ }
86
+ }
87
+ }
88
+
52
89
impl < ' a > EscapedName < ' a > {
53
90
pub fn is_escaped ( & self ) -> bool {
54
91
match & self . 0 . 0 {
@@ -97,9 +134,11 @@ impl Name {
97
134
98
135
/// Resolve a name from the text of token.
99
136
fn resolve ( raw_text : & str ) -> Name {
137
+ // When `raw_text` starts with "r#" but the name does not coincide with any
138
+ // keyword, we never need the prefix so we strip it.
100
139
match raw_text. strip_prefix ( "r#" ) {
101
- Some ( text) => Name :: new_text ( SmolStr :: new ( text) ) ,
102
- None => Name :: new_text ( raw_text. into ( ) ) ,
140
+ Some ( text) if ! is_raw_identifier ( text ) => Name :: new_text ( SmolStr :: new ( text) ) ,
141
+ _ => Name :: new_text ( raw_text. into ( ) ) ,
103
142
}
104
143
}
105
144
@@ -145,6 +184,17 @@ impl Name {
145
184
pub fn escaped ( & self ) -> EscapedName < ' _ > {
146
185
EscapedName ( self )
147
186
}
187
+
188
+ pub fn unescaped ( & self ) -> UnescapedName < ' _ > {
189
+ UnescapedName ( self )
190
+ }
191
+
192
+ pub fn is_escaped ( & self ) -> bool {
193
+ match & self . 0 {
194
+ Repr :: Text ( it) => it. starts_with ( "r#" ) ,
195
+ Repr :: TupleField ( _) => false ,
196
+ }
197
+ }
148
198
}
149
199
150
200
pub trait AsName {
0 commit comments