Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir-expand/src/mod_path.rs')
-rw-r--r--crates/hir-expand/src/mod_path.rs69
1 files changed, 61 insertions, 8 deletions
diff --git a/crates/hir-expand/src/mod_path.rs b/crates/hir-expand/src/mod_path.rs
index d84d978cdb..51e449fe50 100644
--- a/crates/hir-expand/src/mod_path.rs
+++ b/crates/hir-expand/src/mod_path.rs
@@ -2,7 +2,7 @@
use std::{
fmt::{self, Display as _},
- iter,
+ iter::{self, Peekable},
};
use crate::{
@@ -12,10 +12,11 @@ use crate::{
tt,
};
use base_db::Crate;
-use intern::sym;
+use intern::{Symbol, sym};
+use parser::T;
use smallvec::SmallVec;
use span::{Edition, SyntaxContext};
-use syntax::{AstNode, ast};
+use syntax::{AstNode, SyntaxToken, ast};
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct ModPath {
@@ -64,6 +65,58 @@ impl ModPath {
ModPath { kind, segments: SmallVec::new_const() }
}
+ pub fn from_tokens(
+ db: &dyn ExpandDatabase,
+ span_for_range: &mut dyn FnMut(::tt::TextRange) -> SyntaxContext,
+ is_abs: bool,
+ segments: impl Iterator<Item = SyntaxToken>,
+ ) -> Option<ModPath> {
+ let mut segments = segments.peekable();
+ let mut result = SmallVec::new_const();
+ let path_kind = if is_abs {
+ PathKind::Abs
+ } else {
+ let first = segments.next()?;
+ match first.kind() {
+ T![crate] => PathKind::Crate,
+ T![self] => PathKind::Super(handle_super(&mut segments)),
+ T![super] => PathKind::Super(1 + handle_super(&mut segments)),
+ T![ident] => {
+ let first_text = first.text();
+ if first_text == "$crate" {
+ let ctxt = span_for_range(first.text_range());
+ resolve_crate_root(db, ctxt)
+ .map(PathKind::DollarCrate)
+ .unwrap_or(PathKind::Crate)
+ } else {
+ result.push(Name::new_symbol_root(Symbol::intern(first_text)));
+ PathKind::Plain
+ }
+ }
+ _ => return None,
+ }
+ };
+ for segment in segments {
+ if segment.kind() != T![ident] {
+ return None;
+ }
+ result.push(Name::new_symbol_root(Symbol::intern(segment.text())));
+ }
+ if result.is_empty() {
+ return None;
+ }
+ result.shrink_to_fit();
+ return Some(ModPath { kind: path_kind, segments: result });
+
+ fn handle_super(segments: &mut Peekable<impl Iterator<Item = SyntaxToken>>) -> u8 {
+ let mut result = 0;
+ while segments.next_if(|it| it.kind() == T![super]).is_some() {
+ result += 1;
+ }
+ result
+ }
+ }
+
pub fn segments(&self) -> &[Name] {
&self.segments
}
@@ -302,16 +355,16 @@ fn convert_path_tt(db: &dyn ExpandDatabase, tt: tt::TokenTreesView<'_>) -> Optio
tt::Leaf::Punct(tt::Punct { char: ':', .. }) => PathKind::Abs,
_ => return None,
},
- tt::Leaf::Ident(tt::Ident { sym: text, span, .. }) if *text == sym::dollar_crate => {
+ tt::Leaf::Ident(tt::Ident { sym: text, span, .. }) if text == sym::dollar_crate => {
resolve_crate_root(db, span.ctx).map(PathKind::DollarCrate).unwrap_or(PathKind::Crate)
}
- tt::Leaf::Ident(tt::Ident { sym: text, .. }) if *text == sym::self_ => PathKind::SELF,
- tt::Leaf::Ident(tt::Ident { sym: text, .. }) if *text == sym::super_ => {
+ tt::Leaf::Ident(tt::Ident { sym: text, .. }) if text == sym::self_ => PathKind::SELF,
+ tt::Leaf::Ident(tt::Ident { sym: text, .. }) if text == sym::super_ => {
let mut deg = 1;
while let Some(tt::Leaf::Ident(tt::Ident { sym: text, span, is_raw: _ })) =
leaves.next()
{
- if *text != sym::super_ {
+ if text != sym::super_ {
segments.push(Name::new_symbol(text.clone(), span.ctx));
break;
}
@@ -319,7 +372,7 @@ fn convert_path_tt(db: &dyn ExpandDatabase, tt: tt::TokenTreesView<'_>) -> Optio
}
PathKind::Super(deg)
}
- tt::Leaf::Ident(tt::Ident { sym: text, .. }) if *text == sym::crate_ => PathKind::Crate,
+ tt::Leaf::Ident(tt::Ident { sym: text, .. }) if text == sym::crate_ => PathKind::Crate,
tt::Leaf::Ident(ident) => {
segments.push(Name::new_symbol(ident.sym.clone(), ident.span.ctx));
PathKind::Plain