1use std::fmt;
4
5use base_db::SourceDatabase;
6use intern::{Symbol, sym};
7use span::{Edition, SyntaxContext};
8use syntax::utils::is_raw_identifier;
9use syntax::{ast, format_smolstr};
10
11#[derive(Clone, PartialEq, Eq, Hash)]
20pub struct Name {
21 symbol: Symbol,
22 ctx: (),
25}
26
27impl fmt::Debug for Name {
28 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
29 f.debug_struct("Name")
30 .field("symbol", &self.symbol.as_str())
31 .field("ctx", &self.ctx)
32 .finish()
33 }
34}
35
36impl Ord for Name {
37 #[inline]
38 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
39 self.symbol.as_str().cmp(other.symbol.as_str())
40 }
41}
42
43impl PartialOrd for Name {
44 #[inline]
45 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
46 Some(self.cmp(other))
47 }
48}
49
50impl PartialEq<Symbol> for Name {
52 #[inline]
53 fn eq(&self, sym: &Symbol) -> bool {
54 self.symbol == *sym
55 }
56}
57
58impl PartialEq<&Symbol> for Name {
59 #[inline]
60 fn eq(&self, &sym: &&Symbol) -> bool {
61 self.symbol == *sym
62 }
63}
64
65impl PartialEq<Name> for Symbol {
66 #[inline]
67 fn eq(&self, name: &Name) -> bool {
68 *self == name.symbol
69 }
70}
71
72impl PartialEq<Name> for &Symbol {
73 #[inline]
74 fn eq(&self, name: &Name) -> bool {
75 **self == name.symbol
76 }
77}
78
79impl Name {
80 #[inline]
81 fn new_text(text: &str) -> Name {
82 Name { symbol: Symbol::intern(text), ctx: () }
83 }
84
85 #[inline]
86 pub fn new(text: &str, mut ctx: SyntaxContext) -> Name {
87 ctx.remove_root_edition();
91 _ = ctx;
92 let text = text.strip_prefix("r#").unwrap_or(text);
93 Self::new_text(text)
94 }
95
96 #[inline]
97 pub fn new_root(text: &str) -> Name {
98 Self::new(text, SyntaxContext::root(Edition::Edition2015))
100 }
101
102 #[inline]
103 pub fn new_tuple_field(idx: usize) -> Name {
104 Name::new_symbol_root(sym::Integer::get(idx))
105 }
106
107 #[inline]
108 pub fn new_lifetime(lt: &str) -> Name {
109 match lt.strip_prefix("'r#") {
110 Some(lt) => Self::new_text(&format_smolstr!("'{lt}")),
111 None => Self::new_text(lt),
112 }
113 }
114
115 #[inline]
116 pub fn new_symbol(symbol: Symbol, ctx: SyntaxContext) -> Self {
117 debug_assert!(!symbol.as_str().starts_with("r#"));
118 _ = ctx;
119 Self { symbol, ctx: () }
120 }
121
122 #[inline]
124 pub fn new_symbol_root(sym: Symbol) -> Self {
125 Self::new_symbol(sym, SyntaxContext::root(Edition::Edition2015))
126 }
127
128 #[inline]
138 pub const fn missing() -> Name {
139 Name { symbol: sym::MISSING_NAME, ctx: () }
140 }
141
142 #[inline]
148 pub fn is_missing(&self) -> bool {
149 self.symbol == sym::MISSING_NAME
150 }
151
152 #[inline]
156 pub fn generate_new_name(idx: usize) -> Name {
157 Name::new_symbol_root(sym::RaGeneratedName::get(idx))
158 }
159
160 #[inline]
162 pub fn as_tuple_index(&self) -> Option<usize> {
163 sym::Integer::as_uint(&self.symbol)
164 }
165
166 #[inline]
168 pub fn needs_escape(&self, edition: Edition) -> bool {
169 is_raw_identifier(self.symbol.as_str(), edition)
170 }
171
172 #[inline]
177 pub fn as_str(&self) -> &str {
178 self.symbol.as_str()
179 }
180
181 #[inline]
182 pub fn display<'a>(
183 &'a self,
184 db: &dyn SourceDatabase,
185 edition: Edition,
186 ) -> impl fmt::Display + 'a {
187 _ = db;
188 self.display_no_db(edition)
189 }
190
191 #[doc(hidden)]
193 #[inline]
194 pub fn display_no_db(&self, edition: Edition) -> impl fmt::Display + '_ {
195 Display { name: self, edition }
196 }
197
198 #[inline]
199 pub fn symbol(&self) -> &Symbol {
200 &self.symbol
201 }
202
203 #[inline]
204 pub fn is_generated(&self) -> bool {
205 is_generated(self.as_str())
206 }
207}
208
209#[inline]
210pub fn is_generated(name: &str) -> bool {
211 name.starts_with("<ra@gennew>")
212}
213
214struct Display<'a> {
215 name: &'a Name,
216 edition: Edition,
217}
218
219impl fmt::Display for Display<'_> {
220 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
221 let mut symbol = self.name.symbol.as_str();
222
223 if symbol == "'static" {
224 return f.write_str(symbol);
228 }
229
230 if let Some(s) = symbol.strip_prefix('\'') {
231 f.write_str("'")?;
232 symbol = s;
233 }
234 if is_raw_identifier(symbol, self.edition) {
235 f.write_str("r#")?;
236 }
237 f.write_str(symbol)
238 }
239}
240
241pub trait AsName {
242 fn as_name(&self) -> Name;
243}
244
245impl AsName for ast::NameRef {
246 fn as_name(&self) -> Name {
247 match self.as_tuple_field() {
248 Some(idx) => Name::new_tuple_field(idx),
249 None => Name::new_root(&self.text()),
250 }
251 }
252}
253
254impl AsName for ast::Name {
255 fn as_name(&self) -> Name {
256 Name::new_root(&self.text())
257 }
258}
259
260impl AsName for ast::NameOrNameRef {
261 fn as_name(&self) -> Name {
262 match self {
263 ast::NameOrNameRef::Name(it) => it.as_name(),
264 ast::NameOrNameRef::NameRef(it) => it.as_name(),
265 }
266 }
267}
268
269impl AsName for tt::Ident {
270 fn as_name(&self) -> Name {
271 Name::new_root(self.sym.as_str())
272 }
273}
274
275impl AsName for ast::FieldKind {
276 fn as_name(&self) -> Name {
277 match self {
278 ast::FieldKind::Name(nr) => nr.as_name(),
279 ast::FieldKind::Index(idx) => {
280 let idx = idx.text().parse::<usize>().unwrap_or(0);
281 Name::new_tuple_field(idx)
282 }
283 }
284 }
285}
286
287impl AsName for base_db::BuiltDependency {
288 fn as_name(&self) -> Name {
289 Name::new_symbol_root((*self.name).clone())
290 }
291}