aboutsummaryrefslogtreecommitdiff
path: root/crates/hir_expand/src/name.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/hir_expand/src/name.rs')
-rw-r--r--crates/hir_expand/src/name.rs230
1 files changed, 230 insertions, 0 deletions
diff --git a/crates/hir_expand/src/name.rs b/crates/hir_expand/src/name.rs
new file mode 100644
index 000000000..49841c7a1
--- /dev/null
+++ b/crates/hir_expand/src/name.rs
@@ -0,0 +1,230 @@
1//! FIXME: write short doc here
2
3use std::fmt;
4
5use 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)]
11pub struct Name(Repr);
12
13#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
14enum Repr {
15 Text(SmolStr),
16 TupleField(usize),
17}
18
19impl 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
28impl 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: &syntax::SyntaxToken) -> Name {
41 assert!(lt.kind() == syntax::SyntaxKind::LIFETIME);
42 Name(Repr::Text(lt.text().clone()))
43 }
44
45 /// Shortcut to create inline plain text name
46 const fn new_inline_ascii(text: &[u8]) -> Name {
47 Name::new_text(SmolStr::new_inline_from_ascii(text.len(), text))
48 }
49
50 /// Resolve a name from the text of token.
51 fn resolve(raw_text: &SmolStr) -> Name {
52 let raw_start = "r#";
53 if raw_text.as_str().starts_with(raw_start) {
54 Name::new_text(SmolStr::new(&raw_text[raw_start.len()..]))
55 } else {
56 Name::new_text(raw_text.clone())
57 }
58 }
59
60 pub fn missing() -> Name {
61 Name::new_text("[missing name]".into())
62 }
63
64 pub fn as_tuple_index(&self) -> Option<usize> {
65 match self.0 {
66 Repr::TupleField(idx) => Some(idx),
67 _ => None,
68 }
69 }
70}
71
72pub trait AsName {
73 fn as_name(&self) -> Name;
74}
75
76impl AsName for ast::NameRef {
77 fn as_name(&self) -> Name {
78 match self.as_tuple_field() {
79 Some(idx) => Name::new_tuple_field(idx),
80 None => Name::resolve(self.text()),
81 }
82 }
83}
84
85impl AsName for ast::Name {
86 fn as_name(&self) -> Name {
87 Name::resolve(self.text())
88 }
89}
90
91impl AsName for ast::NameOrNameRef {
92 fn as_name(&self) -> Name {
93 match self {
94 ast::NameOrNameRef::Name(it) => it.as_name(),
95 ast::NameOrNameRef::NameRef(it) => it.as_name(),
96 }
97 }
98}
99
100impl AsName for tt::Ident {
101 fn as_name(&self) -> Name {
102 Name::resolve(&self.text)
103 }
104}
105
106impl AsName for ast::FieldKind {
107 fn as_name(&self) -> Name {
108 match self {
109 ast::FieldKind::Name(nr) => nr.as_name(),
110 ast::FieldKind::Index(idx) => {
111 let idx = idx.text().parse::<usize>().unwrap_or(0);
112 Name::new_tuple_field(idx)
113 }
114 }
115 }
116}
117
118impl AsName for base_db::Dependency {
119 fn as_name(&self) -> Name {
120 Name::new_text(SmolStr::new(&*self.name))
121 }
122}
123
124pub mod known {
125 macro_rules! known_names {
126 ($($ident:ident),* $(,)?) => {
127 $(
128 #[allow(bad_style)]
129 pub const $ident: super::Name =
130 super::Name::new_inline_ascii(stringify!($ident).as_bytes());
131 )*
132 };
133 }
134
135 known_names!(
136 // Primitives
137 isize,
138 i8,
139 i16,
140 i32,
141 i64,
142 i128,
143 usize,
144 u8,
145 u16,
146 u32,
147 u64,
148 u128,
149 f32,
150 f64,
151 bool,
152 char,
153 str,
154 // Special names
155 macro_rules,
156 doc,
157 // Components of known path (value or mod name)
158 std,
159 core,
160 alloc,
161 iter,
162 ops,
163 future,
164 result,
165 boxed,
166 // Components of known path (type name)
167 IntoIterator,
168 Item,
169 Try,
170 Ok,
171 Future,
172 Result,
173 Output,
174 Target,
175 Box,
176 RangeFrom,
177 RangeFull,
178 RangeInclusive,
179 RangeToInclusive,
180 RangeTo,
181 Range,
182 Neg,
183 Not,
184 Index,
185 // Builtin macros
186 file,
187 column,
188 compile_error,
189 line,
190 assert,
191 stringify,
192 concat,
193 include,
194 include_bytes,
195 include_str,
196 format_args,
197 format_args_nl,
198 env,
199 option_env,
200 // Builtin derives
201 Copy,
202 Clone,
203 Default,
204 Debug,
205 Hash,
206 Ord,
207 PartialOrd,
208 Eq,
209 PartialEq,
210 );
211
212 // self/Self cannot be used as an identifier
213 pub const SELF_PARAM: super::Name = super::Name::new_inline_ascii(b"self");
214 pub const SELF_TYPE: super::Name = super::Name::new_inline_ascii(b"Self");
215
216 #[macro_export]
217 macro_rules! name {
218 (self) => {
219 $crate::name::known::SELF_PARAM
220 };
221 (Self) => {
222 $crate::name::known::SELF_TYPE
223 };
224 ($ident:ident) => {
225 $crate::name::known::$ident
226 };
227 }
228}
229
230pub use crate::name;