1use std::fmt;
4
5use intern::{Symbol, sym};
6use span::{Edition, SyntaxContext};
7use syntax::utils::is_raw_identifier;
8use syntax::{ast, format_smolstr};
9
10#[derive(Clone, PartialEq, Eq, Hash)]
19pub struct Name {
20 symbol: Symbol,
21 ctx: (),
24}
25
26impl fmt::Debug for Name {
27 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
28 f.debug_struct("Name")
29 .field("symbol", &self.symbol.as_str())
30 .field("ctx", &self.ctx)
31 .finish()
32 }
33}
34
35impl Ord for Name {
36 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
37 self.symbol.as_str().cmp(other.symbol.as_str())
38 }
39}
40
41impl PartialOrd for Name {
42 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
43 Some(self.cmp(other))
44 }
45}
46
47impl PartialEq<Symbol> for Name {
49 fn eq(&self, sym: &Symbol) -> bool {
50 self.symbol == *sym
51 }
52}
53
54impl PartialEq<&Symbol> for Name {
55 fn eq(&self, &sym: &&Symbol) -> bool {
56 self.symbol == *sym
57 }
58}
59
60impl PartialEq<Name> for Symbol {
61 fn eq(&self, name: &Name) -> bool {
62 *self == name.symbol
63 }
64}
65
66impl PartialEq<Name> for &Symbol {
67 fn eq(&self, name: &Name) -> bool {
68 **self == name.symbol
69 }
70}
71
72impl Name {
73 fn new_text(text: &str) -> Name {
74 Name { symbol: Symbol::intern(text), ctx: () }
75 }
76
77 pub fn new(text: &str, mut ctx: SyntaxContext) -> Name {
78 ctx.remove_root_edition();
82 _ = ctx;
83 match text.strip_prefix("r#") {
84 Some(text) => Self::new_text(text),
85 None => Self::new_text(text),
86 }
87 }
88
89 pub fn new_root(text: &str) -> Name {
90 Self::new(text, SyntaxContext::root(Edition::Edition2015))
92 }
93
94 pub fn new_tuple_field(idx: usize) -> Name {
95 let symbol = match idx {
96 0 => sym::INTEGER_0,
97 1 => sym::INTEGER_1,
98 2 => sym::INTEGER_2,
99 3 => sym::INTEGER_3,
100 4 => sym::INTEGER_4,
101 5 => sym::INTEGER_5,
102 6 => sym::INTEGER_6,
103 7 => sym::INTEGER_7,
104 8 => sym::INTEGER_8,
105 9 => sym::INTEGER_9,
106 10 => sym::INTEGER_10,
107 11 => sym::INTEGER_11,
108 12 => sym::INTEGER_12,
109 13 => sym::INTEGER_13,
110 14 => sym::INTEGER_14,
111 15 => sym::INTEGER_15,
112 _ => Symbol::intern(&idx.to_string()),
113 };
114 Name { symbol, ctx: () }
115 }
116
117 pub fn new_lifetime(lt: &str) -> Name {
118 match lt.strip_prefix("'r#") {
119 Some(lt) => Self::new_text(&format_smolstr!("'{lt}")),
120 None => Self::new_text(lt),
121 }
122 }
123
124 pub fn new_symbol(symbol: Symbol, ctx: SyntaxContext) -> Self {
125 debug_assert!(!symbol.as_str().starts_with("r#"));
126 _ = ctx;
127 Self { symbol, ctx: () }
128 }
129
130 pub fn new_symbol_root(sym: Symbol) -> Self {
132 Self::new_symbol(sym, SyntaxContext::root(Edition::Edition2015))
133 }
134
135 pub const fn missing() -> Name {
145 Name { symbol: sym::MISSING_NAME, ctx: () }
146 }
147
148 pub fn is_missing(&self) -> bool {
154 self == &Name::missing()
155 }
156
157 pub fn generate_new_name(idx: usize) -> Name {
161 Name::new_text(&format!("<ra@gennew>{idx}"))
162 }
163
164 pub fn as_tuple_index(&self) -> Option<usize> {
166 self.symbol.as_str().parse().ok()
167 }
168
169 pub fn needs_escape(&self, edition: Edition) -> bool {
171 is_raw_identifier(self.symbol.as_str(), edition)
172 }
173
174 pub fn as_str(&self) -> &str {
179 self.symbol.as_str()
180 }
181
182 pub fn display<'a>(
183 &'a self,
184 db: &dyn crate::db::ExpandDatabase,
185 edition: Edition,
186 ) -> impl fmt::Display + 'a {
187 _ = db;
188 self.display_no_db(edition)
189 }
190
191 #[doc(hidden)]
193 pub fn display_no_db(&self, edition: Edition) -> impl fmt::Display + '_ {
194 Display { name: self, edition }
195 }
196
197 pub fn symbol(&self) -> &Symbol {
198 &self.symbol
199 }
200}
201
202struct Display<'a> {
203 name: &'a Name,
204 edition: Edition,
205}
206
207impl fmt::Display for Display<'_> {
208 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
209 let mut symbol = self.name.symbol.as_str();
210
211 if symbol == "'static" {
212 return f.write_str(symbol);
216 }
217
218 if let Some(s) = symbol.strip_prefix('\'') {
219 f.write_str("'")?;
220 symbol = s;
221 }
222 if is_raw_identifier(symbol, self.edition) {
223 f.write_str("r#")?;
224 }
225 f.write_str(symbol)
226 }
227}
228
229pub trait AsName {
230 fn as_name(&self) -> Name;
231}
232
233impl AsName for ast::NameRef {
234 fn as_name(&self) -> Name {
235 match self.as_tuple_field() {
236 Some(idx) => Name::new_tuple_field(idx),
237 None => Name::new_root(&self.text()),
238 }
239 }
240}
241
242impl AsName for ast::Name {
243 fn as_name(&self) -> Name {
244 Name::new_root(&self.text())
245 }
246}
247
248impl AsName for ast::NameOrNameRef {
249 fn as_name(&self) -> Name {
250 match self {
251 ast::NameOrNameRef::Name(it) => it.as_name(),
252 ast::NameOrNameRef::NameRef(it) => it.as_name(),
253 }
254 }
255}
256
257impl<Span> AsName for tt::Ident<Span> {
258 fn as_name(&self) -> Name {
259 Name::new_root(self.sym.as_str())
260 }
261}
262
263impl AsName for ast::FieldKind {
264 fn as_name(&self) -> Name {
265 match self {
266 ast::FieldKind::Name(nr) => nr.as_name(),
267 ast::FieldKind::Index(idx) => {
268 let idx = idx.text().parse::<usize>().unwrap_or(0);
269 Name::new_tuple_field(idx)
270 }
271 }
272 }
273}
274
275impl AsName for base_db::BuiltDependency {
276 fn as_name(&self) -> Name {
277 Name::new_symbol_root((*self.name).clone())
278 }
279}