Files
rust/crates/libanalysis/src/module_map.rs

282 lines
7.8 KiB
Rust
Raw Normal View History

2018-08-28 18:22:52 +03:00
use relative_path::RelativePathBuf;
2018-08-21 22:24:59 +03:00
use parking_lot::{RwLock, RwLockReadGuard, RwLockWriteGuard};
2018-08-21 18:30:10 +03:00
use libsyntax2::{
2018-08-25 11:44:58 +03:00
File,
2018-08-25 11:40:17 +03:00
ast::{self, AstNode, NameOwner},
2018-08-21 22:24:59 +03:00
SyntaxNode, SmolStr,
2018-08-21 18:30:10 +03:00
};
2018-09-10 12:57:40 +03:00
use {FileId, imp::FileResolverImp};
2018-08-21 18:30:10 +03:00
2018-09-02 20:08:58 +03:00
type SyntaxProvider<'a> = dyn Fn(FileId) -> &'a File + 'a;
2018-08-21 22:24:59 +03:00
2018-08-21 18:30:10 +03:00
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
pub struct ModuleId(FileId);
2018-08-21 22:24:59 +03:00
#[derive(Debug, Default)]
2018-08-21 18:30:10 +03:00
pub struct ModuleMap {
2018-08-21 22:24:59 +03:00
state: RwLock<State>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ChangeKind {
Delete, Insert, Update
}
impl Clone for ModuleMap {
fn clone(&self) -> ModuleMap {
let state = self.state.read().clone();
ModuleMap { state: RwLock::new(state) }
}
}
#[derive(Clone, Debug, Default)]
struct State {
2018-09-10 12:57:40 +03:00
file_resolver: FileResolverImp,
2018-08-21 22:24:59 +03:00
changes: Vec<(FileId, ChangeKind)>,
2018-08-21 18:30:10 +03:00
links: Vec<Link>,
}
#[derive(Clone, Debug)]
struct Link {
owner: ModuleId,
syntax: SyntaxNode,
points_to: Vec<ModuleId>,
2018-08-28 18:22:52 +03:00
problem: Option<Problem>,
}
#[derive(Clone, Debug)]
pub enum Problem {
UnresolvedModule {
candidate: RelativePathBuf,
},
NotDirOwner {
move_to: RelativePathBuf,
candidate: RelativePathBuf,
}
2018-08-21 18:30:10 +03:00
}
impl ModuleMap {
2018-09-03 19:46:30 +03:00
pub fn new() -> ModuleMap {
Default::default()
}
2018-09-10 12:57:40 +03:00
pub fn update_file(&mut self, file_id: FileId, change_kind: ChangeKind) {
self.state.get_mut().changes.push((file_id, change_kind));
}
pub(crate) fn set_file_resolver(&mut self, file_resolver: FileResolverImp) {
self.state.get_mut().file_resolver = file_resolver;
2018-08-21 18:30:10 +03:00
}
pub fn module2file(&self, m: ModuleId) -> FileId {
m.0
}
pub fn file2module(&self, file_id: FileId) -> ModuleId {
ModuleId(file_id)
}
2018-08-21 22:24:59 +03:00
pub fn child_module_by_name<'a>(
&self,
parent_mod: ModuleId,
child_mod: &str,
syntax_provider: &SyntaxProvider,
) -> Vec<ModuleId> {
2018-09-10 12:57:40 +03:00
self.links(syntax_provider)
2018-08-21 22:24:59 +03:00
.links
2018-08-21 18:30:10 +03:00
.iter()
.filter(|link| link.owner == parent_mod)
.filter(|link| link.name() == child_mod)
.filter_map(|it| it.points_to.first())
.map(|&it| it)
.collect()
}
2018-08-21 22:24:59 +03:00
pub fn parent_modules(
&self,
m: ModuleId,
syntax_provider: &SyntaxProvider,
) -> Vec<(ModuleId, SmolStr, SyntaxNode)> {
2018-08-31 19:14:08 +03:00
let mut res = Vec::new();
2018-09-10 12:57:40 +03:00
self.for_each_parent_link(m, syntax_provider, |link| {
2018-08-31 19:14:08 +03:00
res.push(
(link.owner, link.name().clone(), link.syntax.clone())
)
});
res
}
pub fn parent_module_ids(
&self,
m: ModuleId,
syntax_provider: &SyntaxProvider,
) -> Vec<ModuleId> {
let mut res = Vec::new();
2018-09-10 12:57:40 +03:00
self.for_each_parent_link(m, syntax_provider, |link| res.push(link.owner));
2018-08-31 19:14:08 +03:00
res
}
fn for_each_parent_link(
&self,
m: ModuleId,
syntax_provider: &SyntaxProvider,
f: impl FnMut(&Link)
) {
2018-09-10 12:57:40 +03:00
self.links(syntax_provider)
2018-08-21 22:24:59 +03:00
.links
2018-08-21 18:30:10 +03:00
.iter()
.filter(move |link| link.points_to.iter().any(|&it| it == m))
2018-08-31 19:14:08 +03:00
.for_each(f)
2018-08-21 22:24:59 +03:00
}
2018-08-28 18:22:52 +03:00
pub fn problems(
&self,
file: FileId,
syntax_provider: &SyntaxProvider,
mut cb: impl FnMut(ast::Name, &Problem),
) {
let module = self.file2module(file);
2018-09-10 12:57:40 +03:00
let links = self.links(syntax_provider);
2018-08-28 18:22:52 +03:00
links
.links
.iter()
.filter(|link| link.owner == module)
.filter_map(|link| {
let problem = link.problem.as_ref()?;
Some((link, problem))
})
.for_each(|(link, problem)| cb(link.name_node(), problem))
2018-08-27 20:58:38 +03:00
}
2018-08-21 22:24:59 +03:00
fn links(
&self,
syntax_provider: &SyntaxProvider,
) -> RwLockReadGuard<State> {
{
let guard = self.state.read();
if guard.changes.is_empty() {
return guard;
}
}
let mut guard = self.state.write();
if !guard.changes.is_empty() {
2018-09-10 12:57:40 +03:00
guard.apply_changes(syntax_provider);
2018-08-21 22:24:59 +03:00
}
assert!(guard.changes.is_empty());
RwLockWriteGuard::downgrade(guard)
}
}
impl State {
pub fn apply_changes(
&mut self,
syntax_provider: &SyntaxProvider,
) {
let mut reresolve = false;
for (file_id, kind) in self.changes.drain(..) {
let mod_id = ModuleId(file_id);
self.links.retain(|link| link.owner != mod_id);
match kind {
ChangeKind::Delete => {
for link in self.links.iter_mut() {
link.points_to.retain(|&x| x != mod_id);
}
}
ChangeKind::Insert => {
let file = syntax_provider(file_id);
self.links.extend(
file
.ast()
.modules()
.filter_map(|it| Link::new(mod_id, it))
);
reresolve = true;
}
ChangeKind::Update => {
let file = syntax_provider(file_id);
2018-09-10 12:57:40 +03:00
let resolver = &self.file_resolver;
2018-08-21 22:24:59 +03:00
self.links.extend(
file
.ast()
.modules()
.filter_map(|it| Link::new(mod_id, it))
.map(|mut link| {
2018-09-10 12:57:40 +03:00
link.resolve(resolver);
2018-08-21 22:24:59 +03:00
link
})
);
}
}
}
if reresolve {
for link in self.links.iter_mut() {
2018-09-10 12:57:40 +03:00
link.resolve(&self.file_resolver)
2018-08-21 22:24:59 +03:00
}
}
2018-08-21 18:30:10 +03:00
}
}
impl Link {
fn new(owner: ModuleId, module: ast::Module) -> Option<Link> {
if module.name().is_none() {
return None;
}
let link = Link {
owner,
syntax: module.syntax().owned(),
points_to: Vec::new(),
2018-08-28 18:22:52 +03:00
problem: None,
2018-08-21 18:30:10 +03:00
};
Some(link)
}
fn name(&self) -> SmolStr {
2018-08-28 18:22:52 +03:00
self.name_node().text()
}
fn name_node(&self) -> ast::Name {
self.ast().name().unwrap()
2018-08-21 18:30:10 +03:00
}
fn ast(&self) -> ast::Module {
ast::Module::cast(self.syntax.borrowed())
.unwrap()
}
2018-09-10 12:57:40 +03:00
fn resolve(&mut self, file_resolver: &FileResolverImp) {
2018-08-28 20:29:36 +03:00
if !self.ast().has_semi() {
self.problem = None;
self.points_to = Vec::new();
return;
}
2018-09-10 20:14:31 +03:00
let (points_to, problem) = resolve_submodule(self.owner.0, &self.name(), file_resolver);
self.problem = problem;
self.points_to = points_to.into_iter().map(ModuleId).collect();
}
}
2018-08-28 20:29:36 +03:00
2018-09-10 20:14:31 +03:00
pub(crate) fn resolve_submodule(file_id: FileId, name: &SmolStr, file_resolver: &FileResolverImp) -> (Vec<FileId>, Option<Problem>) {
let mod_name = file_resolver.file_stem(file_id);
let is_dir_owner =
mod_name == "mod" || mod_name == "lib" || mod_name == "main";
2018-08-28 18:22:52 +03:00
2018-09-10 20:14:31 +03:00
let file_mod = RelativePathBuf::from(format!("../{}.rs", name));
let dir_mod = RelativePathBuf::from(format!("../{}/mod.rs", name));
let points_to: Vec<FileId>;
let problem: Option<Problem>;
if is_dir_owner {
points_to = [&file_mod, &dir_mod].iter()
.filter_map(|path| file_resolver.resolve(file_id, path))
.collect();
problem = if points_to.is_empty() {
Some(Problem::UnresolvedModule {
2018-08-28 18:22:52 +03:00
candidate: file_mod,
2018-09-10 20:14:31 +03:00
})
} else {
None
2018-08-28 18:22:52 +03:00
}
2018-09-10 20:14:31 +03:00
} else {
points_to = Vec::new();
problem = Some(Problem::NotDirOwner {
move_to: RelativePathBuf::from(format!("../{}/mod.rs", mod_name)),
candidate: file_mod,
});
2018-08-21 18:30:10 +03:00
}
2018-09-10 20:14:31 +03:00
(points_to, problem)
2018-08-21 18:30:10 +03:00
}