• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //! See [`Name`].
2 
3 use std::fmt;
4 
5 use syntax::{ast, utils::is_raw_identifier, SmolStr};
6 
7 /// `Name` is a wrapper around string, which is used in hir for both references
8 /// and declarations. In theory, names should also carry hygiene info, but we are
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#".
14 #[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
15 pub struct Name(Repr);
16 
17 /// Wrapper of `Name` to print the name without "r#" even when it is a raw identifier.
18 #[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
19 pub struct UnescapedName<'a>(&'a Name);
20 
21 #[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
22 enum Repr {
23     Text(SmolStr),
24     TupleField(usize),
25 }
26 
27 impl<'a> UnescapedName<'a> {
28     /// Returns the textual representation of this name as a [`SmolStr`]. Prefer using this over
29     /// [`ToString::to_string`] if possible as this conversion is cheaper in the general case.
to_smol_str(&self) -> SmolStr30     pub fn to_smol_str(&self) -> SmolStr {
31         match &self.0 .0 {
32             Repr::Text(it) => {
33                 if let Some(stripped) = it.strip_prefix("r#") {
34                     SmolStr::new(stripped)
35                 } else {
36                     it.clone()
37                 }
38             }
39             Repr::TupleField(it) => SmolStr::new(it.to_string()),
40         }
41     }
42 
display(&'a self, db: &dyn crate::db::ExpandDatabase) -> impl fmt::Display + 'a43     pub fn display(&'a self, db: &dyn crate::db::ExpandDatabase) -> impl fmt::Display + 'a {
44         _ = db;
45         UnescapedDisplay { name: self }
46     }
47 }
48 
49 impl Name {
50     /// Note: this is private to make creating name from random string hard.
51     /// Hopefully, this should allow us to integrate hygiene cleaner in the
52     /// future, and to switch to interned representation of names.
new_text(text: SmolStr) -> Name53     const fn new_text(text: SmolStr) -> Name {
54         Name(Repr::Text(text))
55     }
56 
new_tuple_field(idx: usize) -> Name57     pub fn new_tuple_field(idx: usize) -> Name {
58         Name(Repr::TupleField(idx))
59     }
60 
new_lifetime(lt: &ast::Lifetime) -> Name61     pub fn new_lifetime(lt: &ast::Lifetime) -> Name {
62         Self::new_text(lt.text().into())
63     }
64 
65     /// Shortcut to create inline plain text name. Panics if `text.len() > 22`
new_inline(text: &str) -> Name66     const fn new_inline(text: &str) -> Name {
67         Name::new_text(SmolStr::new_inline(text))
68     }
69 
70     /// Resolve a name from the text of token.
resolve(raw_text: &str) -> Name71     fn resolve(raw_text: &str) -> Name {
72         match raw_text.strip_prefix("r#") {
73             // When `raw_text` starts with "r#" but the name does not coincide with any
74             // keyword, we never need the prefix so we strip it.
75             Some(text) if !is_raw_identifier(text) => Name::new_text(SmolStr::new(text)),
76             // Keywords (in the current edition) *can* be used as a name in earlier editions of
77             // Rust, e.g. "try" in Rust 2015. Even in such cases, we keep track of them in their
78             // escaped form.
79             None if is_raw_identifier(raw_text) => {
80                 Name::new_text(SmolStr::from_iter(["r#", raw_text]))
81             }
82             _ => Name::new_text(raw_text.into()),
83         }
84     }
85 
86     /// A fake name for things missing in the source code.
87     ///
88     /// For example, `impl Foo for {}` should be treated as a trait impl for a
89     /// type with a missing name. Similarly, `struct S { : u32 }` should have a
90     /// single field with a missing name.
91     ///
92     /// Ideally, we want a `gensym` semantics for missing names -- each missing
93     /// name is equal only to itself. It's not clear how to implement this in
94     /// salsa though, so we punt on that bit for a moment.
missing() -> Name95     pub const fn missing() -> Name {
96         Name::new_inline("[missing name]")
97     }
98 
99     /// Generates a new name which is only equal to itself, by incrementing a counter. Due
100     /// its implementation, it should not be used in things that salsa considers, like
101     /// type names or field names, and it should be only used in names of local variables
102     /// and labels and similar things.
generate_new_name() -> Name103     pub fn generate_new_name() -> Name {
104         use std::sync::atomic::{AtomicUsize, Ordering};
105         static CNT: AtomicUsize = AtomicUsize::new(0);
106         let c = CNT.fetch_add(1, Ordering::Relaxed);
107         Name::new_text(format!("<ra@gennew>{c}").into())
108     }
109 
110     /// Returns the tuple index this name represents if it is a tuple field.
as_tuple_index(&self) -> Option<usize>111     pub fn as_tuple_index(&self) -> Option<usize> {
112         match self.0 {
113             Repr::TupleField(idx) => Some(idx),
114             _ => None,
115         }
116     }
117 
118     /// Returns the text this name represents if it isn't a tuple field.
as_text(&self) -> Option<SmolStr>119     pub fn as_text(&self) -> Option<SmolStr> {
120         match &self.0 {
121             Repr::Text(it) => Some(it.clone()),
122             _ => None,
123         }
124     }
125 
126     /// Returns the text this name represents if it isn't a tuple field.
as_str(&self) -> Option<&str>127     pub fn as_str(&self) -> Option<&str> {
128         match &self.0 {
129             Repr::Text(it) => Some(it),
130             _ => None,
131         }
132     }
133 
134     /// Returns the textual representation of this name as a [`SmolStr`].
135     /// Prefer using this over [`ToString::to_string`] if possible as this conversion is cheaper in
136     /// the general case.
to_smol_str(&self) -> SmolStr137     pub fn to_smol_str(&self) -> SmolStr {
138         match &self.0 {
139             Repr::Text(it) => it.clone(),
140             Repr::TupleField(it) => SmolStr::new(it.to_string()),
141         }
142     }
143 
unescaped(&self) -> UnescapedName<'_>144     pub fn unescaped(&self) -> UnescapedName<'_> {
145         UnescapedName(self)
146     }
147 
is_escaped(&self) -> bool148     pub fn is_escaped(&self) -> bool {
149         match &self.0 {
150             Repr::Text(it) => it.starts_with("r#"),
151             Repr::TupleField(_) => false,
152         }
153     }
154 
display<'a>(&'a self, db: &dyn crate::db::ExpandDatabase) -> impl fmt::Display + 'a155     pub fn display<'a>(&'a self, db: &dyn crate::db::ExpandDatabase) -> impl fmt::Display + 'a {
156         _ = db;
157         Display { name: self }
158     }
159 }
160 
161 struct Display<'a> {
162     name: &'a Name,
163 }
164 
165 impl<'a> fmt::Display for Display<'a> {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result166     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
167         match &self.name.0 {
168             Repr::Text(text) => fmt::Display::fmt(&text, f),
169             Repr::TupleField(idx) => fmt::Display::fmt(&idx, f),
170         }
171     }
172 }
173 
174 struct UnescapedDisplay<'a> {
175     name: &'a UnescapedName<'a>,
176 }
177 
178 impl<'a> fmt::Display for UnescapedDisplay<'a> {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result179     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
180         match &self.name.0 .0 {
181             Repr::Text(text) => {
182                 let text = text.strip_prefix("r#").unwrap_or(text);
183                 fmt::Display::fmt(&text, f)
184             }
185             Repr::TupleField(idx) => fmt::Display::fmt(&idx, f),
186         }
187     }
188 }
189 
190 pub trait AsName {
as_name(&self) -> Name191     fn as_name(&self) -> Name;
192 }
193 
194 impl AsName for ast::NameRef {
as_name(&self) -> Name195     fn as_name(&self) -> Name {
196         match self.as_tuple_field() {
197             Some(idx) => Name::new_tuple_field(idx),
198             None => Name::resolve(&self.text()),
199         }
200     }
201 }
202 
203 impl AsName for ast::Name {
as_name(&self) -> Name204     fn as_name(&self) -> Name {
205         Name::resolve(&self.text())
206     }
207 }
208 
209 impl AsName for ast::NameOrNameRef {
as_name(&self) -> Name210     fn as_name(&self) -> Name {
211         match self {
212             ast::NameOrNameRef::Name(it) => it.as_name(),
213             ast::NameOrNameRef::NameRef(it) => it.as_name(),
214         }
215     }
216 }
217 
218 impl<Span> AsName for tt::Ident<Span> {
as_name(&self) -> Name219     fn as_name(&self) -> Name {
220         Name::resolve(&self.text)
221     }
222 }
223 
224 impl AsName for ast::FieldKind {
as_name(&self) -> Name225     fn as_name(&self) -> Name {
226         match self {
227             ast::FieldKind::Name(nr) => nr.as_name(),
228             ast::FieldKind::Index(idx) => {
229                 let idx = idx.text().parse::<usize>().unwrap_or(0);
230                 Name::new_tuple_field(idx)
231             }
232         }
233     }
234 }
235 
236 impl AsName for base_db::Dependency {
as_name(&self) -> Name237     fn as_name(&self) -> Name {
238         Name::new_text(SmolStr::new(&*self.name))
239     }
240 }
241 
242 pub mod known {
243     macro_rules! known_names {
244         ($($ident:ident),* $(,)?) => {
245             $(
246                 #[allow(bad_style)]
247                 pub const $ident: super::Name =
248                     super::Name::new_inline(stringify!($ident));
249             )*
250         };
251     }
252 
253     known_names!(
254         // Primitives
255         isize,
256         i8,
257         i16,
258         i32,
259         i64,
260         i128,
261         usize,
262         u8,
263         u16,
264         u32,
265         u64,
266         u128,
267         f32,
268         f64,
269         bool,
270         char,
271         str,
272         // Special names
273         macro_rules,
274         doc,
275         cfg,
276         cfg_attr,
277         register_attr,
278         register_tool,
279         // Components of known path (value or mod name)
280         std,
281         core,
282         alloc,
283         iter,
284         ops,
285         future,
286         result,
287         boxed,
288         option,
289         prelude,
290         rust_2015,
291         rust_2018,
292         rust_2021,
293         v1,
294         // Components of known path (type name)
295         Iterator,
296         IntoIterator,
297         Item,
298         IntoIter,
299         Try,
300         Ok,
301         Future,
302         IntoFuture,
303         Result,
304         Option,
305         Output,
306         Target,
307         Box,
308         RangeFrom,
309         RangeFull,
310         RangeInclusive,
311         RangeToInclusive,
312         RangeTo,
313         Range,
314         Neg,
315         Not,
316         None,
317         Index,
318         // Components of known path (function name)
319         filter_map,
320         next,
321         iter_mut,
322         len,
323         is_empty,
324         new,
325         // Builtin macros
326         asm,
327         assert,
328         column,
329         compile_error,
330         concat_idents,
331         concat_bytes,
332         concat,
333         const_format_args,
334         core_panic,
335         env,
336         file,
337         format_args_nl,
338         format_args,
339         global_asm,
340         include_bytes,
341         include_str,
342         include,
343         line,
344         llvm_asm,
345         log_syntax,
346         module_path,
347         option_env,
348         std_panic,
349         stringify,
350         trace_macros,
351         unreachable,
352         // Builtin derives
353         Copy,
354         Clone,
355         Default,
356         Debug,
357         Hash,
358         Ord,
359         PartialOrd,
360         Eq,
361         PartialEq,
362         // Builtin attributes
363         bench,
364         cfg_accessible,
365         cfg_eval,
366         crate_type,
367         derive,
368         global_allocator,
369         no_core,
370         no_std,
371         test,
372         test_case,
373         recursion_limit,
374         feature,
375         // known methods of lang items
376         call_once,
377         call_mut,
378         call,
379         eq,
380         ne,
381         ge,
382         gt,
383         le,
384         lt,
385         // known fields of lang items
386         pieces,
387         // lang items
388         add_assign,
389         add,
390         bitand_assign,
391         bitand,
392         bitor_assign,
393         bitor,
394         bitxor_assign,
395         bitxor,
396         branch,
397         deref_mut,
398         deref,
399         div_assign,
400         div,
401         drop,
402         fn_mut,
403         fn_once,
404         future_trait,
405         index,
406         index_mut,
407         into_future,
408         mul_assign,
409         mul,
410         neg,
411         not,
412         owned_box,
413         partial_ord,
414         poll,
415         r#fn,
416         rem_assign,
417         rem,
418         shl_assign,
419         shl,
420         shr_assign,
421         shr,
422         sub_assign,
423         sub,
424         unsafe_cell,
425         va_list
426     );
427 
428     // self/Self cannot be used as an identifier
429     pub const SELF_PARAM: super::Name = super::Name::new_inline("self");
430     pub const SELF_TYPE: super::Name = super::Name::new_inline("Self");
431 
432     pub const STATIC_LIFETIME: super::Name = super::Name::new_inline("'static");
433 
434     #[macro_export]
435     macro_rules! name {
436         (self) => {
437             $crate::name::known::SELF_PARAM
438         };
439         (Self) => {
440             $crate::name::known::SELF_TYPE
441         };
442         ('static) => {
443             $crate::name::known::STATIC_LIFETIME
444         };
445         ($ident:ident) => {
446             $crate::name::known::$ident
447         };
448     }
449 }
450 
451 pub use crate::name;
452