]> git.lizzy.rs Git - rust.git/blob - crates/ra_hir_expand/src/name.rs
fd02ffa4e12d1ce197771545d31506c354bb6cd6
[rust.git] / crates / ra_hir_expand / src / name.rs
1 //! FIXME: write short doc here
2
3 use std::fmt;
4
5 use ra_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     /// Shortcut to create inline plain text name
41     const fn new_inline_ascii(text: &[u8]) -> Name {
42         Name::new_text(SmolStr::new_inline_from_ascii(text.len(), text))
43     }
44
45     /// Resolve a name from the text of token.
46     fn resolve(raw_text: &SmolStr) -> Name {
47         let raw_start = "r#";
48         if raw_text.as_str().starts_with(raw_start) {
49             Name::new_text(SmolStr::new(&raw_text[raw_start.len()..]))
50         } else {
51             Name::new_text(raw_text.clone())
52         }
53     }
54
55     pub fn missing() -> Name {
56         Name::new_text("[missing name]".into())
57     }
58
59     pub fn as_tuple_index(&self) -> Option<usize> {
60         match self.0 {
61             Repr::TupleField(idx) => Some(idx),
62             _ => None,
63         }
64     }
65 }
66
67 pub trait AsName {
68     fn as_name(&self) -> Name;
69 }
70
71 impl AsName for ast::NameRef {
72     fn as_name(&self) -> Name {
73         match self.as_tuple_field() {
74             Some(idx) => Name::new_tuple_field(idx),
75             None => Name::resolve(self.text()),
76         }
77     }
78 }
79
80 impl AsName for ast::Name {
81     fn as_name(&self) -> Name {
82         Name::resolve(self.text())
83     }
84 }
85
86 impl AsName for tt::Ident {
87     fn as_name(&self) -> Name {
88         Name::resolve(&self.text)
89     }
90 }
91
92 impl AsName for ast::FieldKind {
93     fn as_name(&self) -> Name {
94         match self {
95             ast::FieldKind::Name(nr) => nr.as_name(),
96             ast::FieldKind::Index(idx) => Name::new_tuple_field(idx.text().parse().unwrap()),
97         }
98     }
99 }
100
101 impl AsName for ra_db::Dependency {
102     fn as_name(&self) -> Name {
103         Name::new_text(self.name.clone())
104     }
105 }
106
107 pub mod known {
108     macro_rules! known_names {
109         ($($ident:ident),* $(,)?) => {
110             $(
111                 #[allow(bad_style)]
112                 pub const $ident: super::Name =
113                     super::Name::new_inline_ascii(stringify!($ident).as_bytes());
114             )*
115         };
116     }
117
118     known_names!(
119         // Primitives
120         isize,
121         i8,
122         i16,
123         i32,
124         i64,
125         i128,
126         usize,
127         u8,
128         u16,
129         u32,
130         u64,
131         u128,
132         f32,
133         f64,
134         bool,
135         char,
136         str,
137         // Special names
138         macro_rules,
139         // Components of known path (value or mod name)
140         std,
141         iter,
142         ops,
143         future,
144         result,
145         boxed,
146         // Components of known path (type name)
147         IntoIterator,
148         Item,
149         Try,
150         Ok,
151         Future,
152         Result,
153         Output,
154         Target,
155         Box,
156         RangeFrom,
157         RangeFull,
158         RangeInclusive,
159         RangeToInclusive,
160         RangeTo,
161         Range,
162         Neg,
163         Not,
164         Index,
165         // Builtin macros
166         file,
167         column,
168         compile_error,
169         line,
170         stringify,
171         format_args,
172         format_args_nl,
173         // Builtin derives
174         Copy,
175         Clone,
176         Default,
177         Debug,
178         Hash,
179         Ord,
180         PartialOrd,
181         Eq,
182         PartialEq,
183     );
184
185     // self/Self cannot be used as an identifier
186     pub const SELF_PARAM: super::Name = super::Name::new_inline_ascii(b"self");
187     pub const SELF_TYPE: super::Name = super::Name::new_inline_ascii(b"Self");
188
189     #[macro_export]
190     macro_rules! name {
191         (self) => {
192             $crate::name::known::SELF_PARAM
193         };
194         (Self) => {
195             $crate::name::known::SELF_TYPE
196         };
197         ($ident:ident) => {
198             $crate::name::known::$ident
199         };
200     }
201 }
202
203 pub use crate::name;