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.rs59
1 files changed, 56 insertions, 3 deletions
diff --git a/crates/hir-expand/src/mod_path.rs b/crates/hir-expand/src/mod_path.rs
index d84d978cdb..e9805e3f86 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
}