aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir_def/src/path.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir_def/src/path.rs')
-rw-r--r--crates/ra_hir_def/src/path.rs423
1 files changed, 423 insertions, 0 deletions
diff --git a/crates/ra_hir_def/src/path.rs b/crates/ra_hir_def/src/path.rs
new file mode 100644
index 000000000..fe060437d
--- /dev/null
+++ b/crates/ra_hir_def/src/path.rs
@@ -0,0 +1,423 @@
1//! FIXME: write short doc here
2
3use std::{iter, sync::Arc};
4
5use hir_expand::db::AstDatabase;
6use ra_db::CrateId;
7use ra_syntax::{
8 ast::{self, NameOwner, TypeAscriptionOwner},
9 AstNode,
10};
11
12use crate::{
13 name::{self, AsName, Name},
14 type_ref::TypeRef,
15 Source,
16};
17
18#[derive(Debug, Clone, PartialEq, Eq, Hash)]
19pub struct Path {
20 pub kind: PathKind,
21 pub segments: Vec<PathSegment>,
22}
23
24#[derive(Debug, Clone, PartialEq, Eq, Hash)]
25pub struct PathSegment {
26 pub name: Name,
27 pub args_and_bindings: Option<Arc<GenericArgs>>,
28}
29
30/// Generic arguments to a path segment (e.g. the `i32` in `Option<i32>`). This
31/// can (in the future) also include bindings of associated types, like in
32/// `Iterator<Item = Foo>`.
33#[derive(Debug, Clone, PartialEq, Eq, Hash)]
34pub struct GenericArgs {
35 pub args: Vec<GenericArg>,
36 /// This specifies whether the args contain a Self type as the first
37 /// element. This is the case for path segments like `<T as Trait>`, where
38 /// `T` is actually a type parameter for the path `Trait` specifying the
39 /// Self type. Otherwise, when we have a path `Trait<X, Y>`, the Self type
40 /// is left out.
41 pub has_self_type: bool,
42 /// Associated type bindings like in `Iterator<Item = T>`.
43 pub bindings: Vec<(Name, TypeRef)>,
44}
45
46/// A single generic argument.
47#[derive(Debug, Clone, PartialEq, Eq, Hash)]
48pub enum GenericArg {
49 Type(TypeRef),
50 // or lifetime...
51}
52
53#[derive(Debug, Clone, PartialEq, Eq, Hash)]
54pub enum PathKind {
55 Plain,
56 Self_,
57 Super,
58 Crate,
59 // Absolute path
60 Abs,
61 // Type based path like `<T>::foo`
62 Type(Box<TypeRef>),
63 // `$crate` from macro expansion
64 DollarCrate(CrateId),
65}
66
67impl Path {
68 /// Calls `cb` with all paths, represented by this use item.
69 pub fn expand_use_item(
70 item_src: Source<ast::UseItem>,
71 db: &impl AstDatabase,
72 mut cb: impl FnMut(Path, &ast::UseTree, bool, Option<Name>),
73 ) {
74 if let Some(tree) = item_src.ast.use_tree() {
75 expand_use_tree(None, tree, &|| item_src.file_id.macro_crate(db), &mut cb);
76 }
77 }
78
79 pub fn from_simple_segments(kind: PathKind, segments: impl IntoIterator<Item = Name>) -> Path {
80 Path {
81 kind,
82 segments: segments
83 .into_iter()
84 .map(|name| PathSegment { name, args_and_bindings: None })
85 .collect(),
86 }
87 }
88
89 /// Converts an `ast::Path` to `Path`. Works with use trees.
90 /// DEPRECATED: It does not handle `$crate` from macro call.
91 pub fn from_ast(path: ast::Path) -> Option<Path> {
92 Path::parse(path, &|| None)
93 }
94
95 /// Converts an `ast::Path` to `Path`. Works with use trees.
96 /// It correctly handles `$crate` based path from macro call.
97 pub fn from_src(source: Source<ast::Path>, db: &impl AstDatabase) -> Option<Path> {
98 let file_id = source.file_id;
99 Path::parse(source.ast, &|| file_id.macro_crate(db))
100 }
101
102 fn parse(mut path: ast::Path, macro_crate: &impl Fn() -> Option<CrateId>) -> Option<Path> {
103 let mut kind = PathKind::Plain;
104 let mut segments = Vec::new();
105 loop {
106 let segment = path.segment()?;
107
108 if segment.has_colon_colon() {
109 kind = PathKind::Abs;
110 }
111
112 match segment.kind()? {
113 ast::PathSegmentKind::Name(name) => {
114 if name.text() == "$crate" {
115 if let Some(macro_crate) = macro_crate() {
116 kind = PathKind::DollarCrate(macro_crate);
117 break;
118 }
119 }
120
121 let args = segment
122 .type_arg_list()
123 .and_then(GenericArgs::from_ast)
124 .or_else(|| {
125 GenericArgs::from_fn_like_path_ast(
126 segment.param_list(),
127 segment.ret_type(),
128 )
129 })
130 .map(Arc::new);
131 let segment = PathSegment { name: name.as_name(), args_and_bindings: args };
132 segments.push(segment);
133 }
134 ast::PathSegmentKind::Type { type_ref, trait_ref } => {
135 assert!(path.qualifier().is_none()); // this can only occur at the first segment
136
137 let self_type = TypeRef::from_ast(type_ref?);
138
139 match trait_ref {
140 // <T>::foo
141 None => {
142 kind = PathKind::Type(Box::new(self_type));
143 }
144 // <T as Trait<A>>::Foo desugars to Trait<Self=T, A>::Foo
145 Some(trait_ref) => {
146 let path = Path::parse(trait_ref.path()?, macro_crate)?;
147 kind = path.kind;
148 let mut prefix_segments = path.segments;
149 prefix_segments.reverse();
150 segments.extend(prefix_segments);
151 // Insert the type reference (T in the above example) as Self parameter for the trait
152 let mut last_segment = segments.last_mut()?;
153 if last_segment.args_and_bindings.is_none() {
154 last_segment.args_and_bindings =
155 Some(Arc::new(GenericArgs::empty()));
156 };
157 let args = last_segment.args_and_bindings.as_mut().unwrap();
158 let mut args_inner = Arc::make_mut(args);
159 args_inner.has_self_type = true;
160 args_inner.args.insert(0, GenericArg::Type(self_type));
161 }
162 }
163 }
164 ast::PathSegmentKind::CrateKw => {
165 kind = PathKind::Crate;
166 break;
167 }
168 ast::PathSegmentKind::SelfKw => {
169 kind = PathKind::Self_;
170 break;
171 }
172 ast::PathSegmentKind::SuperKw => {
173 kind = PathKind::Super;
174 break;
175 }
176 }
177 path = match qualifier(&path) {
178 Some(it) => it,
179 None => break,
180 };
181 }
182 segments.reverse();
183 return Some(Path { kind, segments });
184
185 fn qualifier(path: &ast::Path) -> Option<ast::Path> {
186 if let Some(q) = path.qualifier() {
187 return Some(q);
188 }
189 // FIXME: this bottom up traversal is not too precise.
190 // Should we handle do a top-down analysis, recording results?
191 let use_tree_list = path.syntax().ancestors().find_map(ast::UseTreeList::cast)?;
192 let use_tree = use_tree_list.parent_use_tree();
193 use_tree.path()
194 }
195 }
196
197 /// Converts an `ast::NameRef` into a single-identifier `Path`.
198 pub fn from_name_ref(name_ref: &ast::NameRef) -> Path {
199 name_ref.as_name().into()
200 }
201
202 /// `true` is this path is a single identifier, like `foo`
203 pub fn is_ident(&self) -> bool {
204 self.kind == PathKind::Plain && self.segments.len() == 1
205 }
206
207 /// `true` if this path is just a standalone `self`
208 pub fn is_self(&self) -> bool {
209 self.kind == PathKind::Self_ && self.segments.is_empty()
210 }
211
212 /// If this path is a single identifier, like `foo`, return its name.
213 pub fn as_ident(&self) -> Option<&Name> {
214 if self.kind != PathKind::Plain || self.segments.len() > 1 {
215 return None;
216 }
217 self.segments.first().map(|s| &s.name)
218 }
219
220 pub fn expand_macro_expr(&self) -> Option<Name> {
221 self.as_ident().and_then(|name| Some(name.clone()))
222 }
223
224 pub fn is_type_relative(&self) -> bool {
225 match self.kind {
226 PathKind::Type(_) => true,
227 _ => false,
228 }
229 }
230}
231
232impl GenericArgs {
233 pub fn from_ast(node: ast::TypeArgList) -> Option<GenericArgs> {
234 let mut args = Vec::new();
235 for type_arg in node.type_args() {
236 let type_ref = TypeRef::from_ast_opt(type_arg.type_ref());
237 args.push(GenericArg::Type(type_ref));
238 }
239 // lifetimes ignored for now
240 let mut bindings = Vec::new();
241 for assoc_type_arg in node.assoc_type_args() {
242 if let Some(name_ref) = assoc_type_arg.name_ref() {
243 let name = name_ref.as_name();
244 let type_ref = TypeRef::from_ast_opt(assoc_type_arg.type_ref());
245 bindings.push((name, type_ref));
246 }
247 }
248 if args.is_empty() && bindings.is_empty() {
249 None
250 } else {
251 Some(GenericArgs { args, has_self_type: false, bindings })
252 }
253 }
254
255 /// Collect `GenericArgs` from the parts of a fn-like path, i.e. `Fn(X, Y)
256 /// -> Z` (which desugars to `Fn<(X, Y), Output=Z>`).
257 pub(crate) fn from_fn_like_path_ast(
258 params: Option<ast::ParamList>,
259 ret_type: Option<ast::RetType>,
260 ) -> Option<GenericArgs> {
261 let mut args = Vec::new();
262 let mut bindings = Vec::new();
263 if let Some(params) = params {
264 let mut param_types = Vec::new();
265 for param in params.params() {
266 let type_ref = TypeRef::from_ast_opt(param.ascribed_type());
267 param_types.push(type_ref);
268 }
269 let arg = GenericArg::Type(TypeRef::Tuple(param_types));
270 args.push(arg);
271 }
272 if let Some(ret_type) = ret_type {
273 let type_ref = TypeRef::from_ast_opt(ret_type.type_ref());
274 bindings.push((name::OUTPUT_TYPE, type_ref))
275 }
276 if args.is_empty() && bindings.is_empty() {
277 None
278 } else {
279 Some(GenericArgs { args, has_self_type: false, bindings })
280 }
281 }
282
283 pub(crate) fn empty() -> GenericArgs {
284 GenericArgs { args: Vec::new(), has_self_type: false, bindings: Vec::new() }
285 }
286}
287
288impl From<Name> for Path {
289 fn from(name: Name) -> Path {
290 Path::from_simple_segments(PathKind::Plain, iter::once(name))
291 }
292}
293
294fn expand_use_tree(
295 prefix: Option<Path>,
296 tree: ast::UseTree,
297 macro_crate: &impl Fn() -> Option<CrateId>,
298 cb: &mut impl FnMut(Path, &ast::UseTree, bool, Option<Name>),
299) {
300 if let Some(use_tree_list) = tree.use_tree_list() {
301 let prefix = match tree.path() {
302 // E.g. use something::{{{inner}}};
303 None => prefix,
304 // E.g. `use something::{inner}` (prefix is `None`, path is `something`)
305 // or `use something::{path::{inner::{innerer}}}` (prefix is `something::path`, path is `inner`)
306 Some(path) => match convert_path(prefix, path, macro_crate) {
307 Some(it) => Some(it),
308 None => return, // FIXME: report errors somewhere
309 },
310 };
311 for child_tree in use_tree_list.use_trees() {
312 expand_use_tree(prefix.clone(), child_tree, macro_crate, cb);
313 }
314 } else {
315 let alias = tree.alias().and_then(|a| a.name()).map(|a| a.as_name());
316 if let Some(ast_path) = tree.path() {
317 // Handle self in a path.
318 // E.g. `use something::{self, <...>}`
319 if ast_path.qualifier().is_none() {
320 if let Some(segment) = ast_path.segment() {
321 if segment.kind() == Some(ast::PathSegmentKind::SelfKw) {
322 if let Some(prefix) = prefix {
323 cb(prefix, &tree, false, alias);
324 return;
325 }
326 }
327 }
328 }
329 if let Some(path) = convert_path(prefix, ast_path, macro_crate) {
330 let is_glob = tree.has_star();
331 cb(path, &tree, is_glob, alias)
332 }
333 // FIXME: report errors somewhere
334 // We get here if we do
335 }
336 }
337}
338
339fn convert_path(
340 prefix: Option<Path>,
341 path: ast::Path,
342 macro_crate: &impl Fn() -> Option<CrateId>,
343) -> Option<Path> {
344 let prefix = if let Some(qual) = path.qualifier() {
345 Some(convert_path(prefix, qual, macro_crate)?)
346 } else {
347 prefix
348 };
349
350 let segment = path.segment()?;
351 let res = match segment.kind()? {
352 ast::PathSegmentKind::Name(name) => {
353 if name.text() == "$crate" {
354 if let Some(krate) = macro_crate() {
355 return Some(Path::from_simple_segments(
356 PathKind::DollarCrate(krate),
357 iter::empty(),
358 ));
359 }
360 }
361
362 // no type args in use
363 let mut res = prefix
364 .unwrap_or_else(|| Path { kind: PathKind::Plain, segments: Vec::with_capacity(1) });
365 res.segments.push(PathSegment {
366 name: name.as_name(),
367 args_and_bindings: None, // no type args in use
368 });
369 res
370 }
371 ast::PathSegmentKind::CrateKw => {
372 if prefix.is_some() {
373 return None;
374 }
375 Path::from_simple_segments(PathKind::Crate, iter::empty())
376 }
377 ast::PathSegmentKind::SelfKw => {
378 if prefix.is_some() {
379 return None;
380 }
381 Path::from_simple_segments(PathKind::Self_, iter::empty())
382 }
383 ast::PathSegmentKind::SuperKw => {
384 if prefix.is_some() {
385 return None;
386 }
387 Path::from_simple_segments(PathKind::Super, iter::empty())
388 }
389 ast::PathSegmentKind::Type { .. } => {
390 // not allowed in imports
391 return None;
392 }
393 };
394 Some(res)
395}
396
397pub mod known {
398 use super::{Path, PathKind};
399 use crate::name;
400
401 pub fn std_iter_into_iterator() -> Path {
402 Path::from_simple_segments(
403 PathKind::Abs,
404 vec![name::STD, name::ITER, name::INTO_ITERATOR_TYPE],
405 )
406 }
407
408 pub fn std_ops_try() -> Path {
409 Path::from_simple_segments(PathKind::Abs, vec![name::STD, name::OPS, name::TRY_TYPE])
410 }
411
412 pub fn std_result_result() -> Path {
413 Path::from_simple_segments(PathKind::Abs, vec![name::STD, name::RESULT, name::RESULT_TYPE])
414 }
415
416 pub fn std_future_future() -> Path {
417 Path::from_simple_segments(PathKind::Abs, vec![name::STD, name::FUTURE, name::FUTURE_TYPE])
418 }
419
420 pub fn std_boxed_box() -> Path {
421 Path::from_simple_segments(PathKind::Abs, vec![name::STD, name::BOXED, name::BOX_TYPE])
422 }
423}