]> git.lizzy.rs Git - rust.git/blob - crates/hir-expand/src/name.rs
Auto merge of #12652 - lnicola:openvsx, r=lnicola
[rust.git] / crates / hir-expand / src / name.rs
1 //! See [`Name`].
2
3 use std::fmt;
4
5 use syntax::{ast, 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 #[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
11 pub struct Name(Repr);
12
13 #[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
14 enum Repr {
15     Text(SmolStr),
16     TupleField(usize),
17 }
18
19 impl fmt::Display for Name {
20     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
21         match &self.0 {
22             Repr::Text(text) => fmt::Display::fmt(&text, f),
23             Repr::TupleField(idx) => fmt::Display::fmt(&idx, f),
24         }
25     }
26 }
27
28 impl Name {
29     /// Note: this is private to make creating name from random string hard.
30     /// Hopefully, this should allow us to integrate hygiene cleaner in the
31     /// future, and to switch to interned representation of names.
32     const fn new_text(text: SmolStr) -> Name {
33         Name(Repr::Text(text))
34     }
35
36     pub fn new_tuple_field(idx: usize) -> Name {
37         Name(Repr::TupleField(idx))
38     }
39
40     pub fn new_lifetime(lt: &ast::Lifetime) -> Name {
41         Self::new_text(lt.text().into())
42     }
43
44     /// Shortcut to create inline plain text name
45     const fn new_inline(text: &str) -> Name {
46         Name::new_text(SmolStr::new_inline(text))
47     }
48
49     /// Resolve a name from the text of token.
50     fn resolve(raw_text: &str) -> Name {
51         match raw_text.strip_prefix("r#") {
52             Some(text) => Name::new_text(SmolStr::new(text)),
53             None => Name::new_text(raw_text.into()),
54         }
55     }
56
57     /// A fake name for things missing in the source code.
58     ///
59     /// For example, `impl Foo for {}` should be treated as a trait impl for a
60     /// type with a missing name. Similarly, `struct S { : u32 }` should have a
61     /// single field with a missing name.
62     ///
63     /// Ideally, we want a `gensym` semantics for missing names -- each missing
64     /// name is equal only to itself. It's not clear how to implement this in
65     /// salsa though, so we punt on that bit for a moment.
66     pub const fn missing() -> Name {
67         Name::new_inline("[missing name]")
68     }
69
70     /// Returns the tuple index this name represents if it is a tuple field.
71     pub fn as_tuple_index(&self) -> Option<usize> {
72         match self.0 {
73             Repr::TupleField(idx) => Some(idx),
74             _ => None,
75         }
76     }
77
78     /// Returns the text this name represents if it isn't a tuple field.
79     pub fn as_text(&self) -> Option<SmolStr> {
80         match &self.0 {
81             Repr::Text(it) => Some(it.clone()),
82             _ => None,
83         }
84     }
85
86     /// Returns the textual representation of this name as a [`SmolStr`].
87     /// Prefer using this over [`ToString::to_string`] if possible as this conversion is cheaper in
88     /// the general case.
89     pub fn to_smol_str(&self) -> SmolStr {
90         match &self.0 {
91             Repr::Text(it) => it.clone(),
92             Repr::TupleField(it) => SmolStr::new(&it.to_string()),
93         }
94     }
95 }
96
97 pub trait AsName {
98     fn as_name(&self) -> Name;
99 }
100
101 impl AsName for ast::NameRef {
102     fn as_name(&self) -> Name {
103         match self.as_tuple_field() {
104             Some(idx) => Name::new_tuple_field(idx),
105             None => Name::resolve(&self.text()),
106         }
107     }
108 }
109
110 impl AsName for ast::Name {
111     fn as_name(&self) -> Name {
112         Name::resolve(&self.text())
113     }
114 }
115
116 impl AsName for ast::NameOrNameRef {
117     fn as_name(&self) -> Name {
118         match self {
119             ast::NameOrNameRef::Name(it) => it.as_name(),
120             ast::NameOrNameRef::NameRef(it) => it.as_name(),
121         }
122     }
123 }
124
125 impl AsName for tt::Ident {
126     fn as_name(&self) -> Name {
127         Name::resolve(&self.text)
128     }
129 }
130
131 impl AsName for ast::FieldKind {
132     fn as_name(&self) -> Name {
133         match self {
134             ast::FieldKind::Name(nr) => nr.as_name(),
135             ast::FieldKind::Index(idx) => {
136                 let idx = idx.text().parse::<usize>().unwrap_or(0);
137                 Name::new_tuple_field(idx)
138             }
139         }
140     }
141 }
142
143 impl AsName for base_db::Dependency {
144     fn as_name(&self) -> Name {
145         Name::new_text(SmolStr::new(&*self.name))
146     }
147 }
148
149 pub mod known {
150     macro_rules! known_names {
151         ($($ident:ident),* $(,)?) => {
152             $(
153                 #[allow(bad_style)]
154                 pub const $ident: super::Name =
155                     super::Name::new_inline(stringify!($ident));
156             )*
157         };
158     }
159
160     known_names!(
161         // Primitives
162         isize,
163         i8,
164         i16,
165         i32,
166         i64,
167         i128,
168         usize,
169         u8,
170         u16,
171         u32,
172         u64,
173         u128,
174         f32,
175         f64,
176         bool,
177         char,
178         str,
179         // Special names
180         macro_rules,
181         doc,
182         cfg,
183         cfg_attr,
184         register_attr,
185         register_tool,
186         // Components of known path (value or mod name)
187         std,
188         core,
189         alloc,
190         iter,
191         ops,
192         future,
193         result,
194         boxed,
195         option,
196         prelude,
197         rust_2015,
198         rust_2018,
199         rust_2021,
200         v1,
201         // Components of known path (type name)
202         Iterator,
203         IntoIterator,
204         Item,
205         Try,
206         Ok,
207         Future,
208         Result,
209         Option,
210         Output,
211         Target,
212         Box,
213         RangeFrom,
214         RangeFull,
215         RangeInclusive,
216         RangeToInclusive,
217         RangeTo,
218         Range,
219         Neg,
220         Not,
221         None,
222         Index,
223         // Components of known path (function name)
224         filter_map,
225         next,
226         iter_mut,
227         len,
228         is_empty,
229         new,
230         // Builtin macros
231         asm,
232         assert,
233         column,
234         compile_error,
235         concat_idents,
236         concat_bytes,
237         concat,
238         const_format_args,
239         core_panic,
240         env,
241         file,
242         format_args_nl,
243         format_args,
244         global_asm,
245         include_bytes,
246         include_str,
247         include,
248         line,
249         llvm_asm,
250         log_syntax,
251         module_path,
252         option_env,
253         std_panic,
254         stringify,
255         trace_macros,
256         unreachable,
257         // Builtin derives
258         Copy,
259         Clone,
260         Default,
261         Debug,
262         Hash,
263         Ord,
264         PartialOrd,
265         Eq,
266         PartialEq,
267         // Builtin attributes
268         bench,
269         cfg_accessible,
270         cfg_eval,
271         crate_type,
272         derive,
273         global_allocator,
274         test,
275         test_case,
276         recursion_limit,
277         // Safe intrinsics
278         abort,
279         add_with_overflow,
280         black_box,
281         bitreverse,
282         bswap,
283         caller_location,
284         ctlz,
285         ctpop,
286         cttz,
287         discriminant_value,
288         forget,
289         likely,
290         maxnumf32,
291         maxnumf64,
292         min_align_of_val,
293         min_align_of,
294         minnumf32,
295         minnumf64,
296         mul_with_overflow,
297         needs_drop,
298         ptr_guaranteed_eq,
299         ptr_guaranteed_ne,
300         rotate_left,
301         rotate_right,
302         rustc_peek,
303         saturating_add,
304         saturating_sub,
305         size_of_val,
306         size_of,
307         sub_with_overflow,
308         type_id,
309         type_name,
310         unlikely,
311         variant_count,
312         wrapping_add,
313         wrapping_mul,
314         wrapping_sub,
315         // known methods of lang items
316         eq,
317         ne,
318         ge,
319         gt,
320         le,
321         lt,
322         // lang items
323         add_assign,
324         add,
325         bitand_assign,
326         bitand,
327         bitor_assign,
328         bitor,
329         bitxor_assign,
330         bitxor,
331         deref_mut,
332         deref,
333         div_assign,
334         div,
335         fn_mut,
336         fn_once,
337         future_trait,
338         index,
339         index_mut,
340         mul_assign,
341         mul,
342         neg,
343         not,
344         owned_box,
345         partial_ord,
346         r#fn,
347         rem_assign,
348         rem,
349         shl_assign,
350         shl,
351         shr_assign,
352         shr,
353         sub_assign,
354         sub,
355     );
356
357     // self/Self cannot be used as an identifier
358     pub const SELF_PARAM: super::Name = super::Name::new_inline("self");
359     pub const SELF_TYPE: super::Name = super::Name::new_inline("Self");
360
361     pub const STATIC_LIFETIME: super::Name = super::Name::new_inline("'static");
362
363     #[macro_export]
364     macro_rules! name {
365         (self) => {
366             $crate::name::known::SELF_PARAM
367         };
368         (Self) => {
369             $crate::name::known::SELF_TYPE
370         };
371         ('static) => {
372             $crate::name::known::STATIC_LIFETIME
373         };
374         ($ident:ident) => {
375             $crate::name::known::$ident
376         };
377     }
378 }
379
380 pub use crate::name;