mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-26 20:09:19 +00:00
flatten module structure
This commit is contained in:
parent
5a505189a8
commit
fd4456d0ec
13 changed files with 431 additions and 436 deletions
|
@ -1,7 +1,8 @@
|
||||||
|
use relative_path::RelativePathBuf;
|
||||||
use ra_db::{CrateId, Cancelable, FileId};
|
use ra_db::{CrateId, Cancelable, FileId};
|
||||||
use ra_syntax::{ast, SyntaxNode};
|
use ra_syntax::{ast, SyntaxNode};
|
||||||
|
|
||||||
use crate::{Name, db::HirDatabase, DefId, Path, PerNs, module::{Problem, ModuleScope}};
|
use crate::{Name, db::HirDatabase, DefId, Path, PerNs, nameres::ModuleScope};
|
||||||
|
|
||||||
/// hir::Crate describes a single crate. It's the main inteface with which
|
/// hir::Crate describes a single crate. It's the main inteface with which
|
||||||
/// crate's dependencies interact. Mostly, it should be just a proxy for the
|
/// crate's dependencies interact. Mostly, it should be just a proxy for the
|
||||||
|
@ -39,6 +40,17 @@ pub enum ModuleSource {
|
||||||
Module(ast::ModuleNode),
|
Module(ast::ModuleNode),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
|
||||||
|
pub enum Problem {
|
||||||
|
UnresolvedModule {
|
||||||
|
candidate: RelativePathBuf,
|
||||||
|
},
|
||||||
|
NotDirOwner {
|
||||||
|
move_to: RelativePathBuf,
|
||||||
|
candidate: RelativePathBuf,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
impl Module {
|
impl Module {
|
||||||
/// Name of this module.
|
/// Name of this module.
|
||||||
pub fn name(&self, db: &impl HirDatabase) -> Cancelable<Option<Name>> {
|
pub fn name(&self, db: &impl HirDatabase) -> Cancelable<Option<Name>> {
|
||||||
|
|
|
@ -1,194 +1,2 @@
|
||||||
use ra_db::{CrateId, Cancelable, SourceRootId, FileId};
|
mod krate; // `crate` is invalid ident :(
|
||||||
use ra_syntax::{ast, SyntaxNode, AstNode};
|
pub(crate) mod module;
|
||||||
|
|
||||||
use crate::{
|
|
||||||
HirFileId, Crate, CrateDependency, AsName, DefId, DefLoc, DefKind, Name, Path, PathKind, PerNs, Def, ModuleId,
|
|
||||||
module::{ModuleScope, Problem},
|
|
||||||
db::HirDatabase,
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::code_model_api::{Module, ModuleSource};
|
|
||||||
|
|
||||||
impl Crate {
|
|
||||||
pub(crate) fn new(crate_id: CrateId) -> Crate {
|
|
||||||
Crate { crate_id }
|
|
||||||
}
|
|
||||||
pub(crate) fn dependencies_impl(&self, db: &impl HirDatabase) -> Vec<CrateDependency> {
|
|
||||||
let crate_graph = db.crate_graph();
|
|
||||||
crate_graph
|
|
||||||
.dependencies(self.crate_id)
|
|
||||||
.map(|dep| {
|
|
||||||
let krate = Crate::new(dep.crate_id());
|
|
||||||
let name = dep.as_name();
|
|
||||||
CrateDependency { krate, name }
|
|
||||||
})
|
|
||||||
.collect()
|
|
||||||
}
|
|
||||||
pub(crate) fn root_module_impl(&self, db: &impl HirDatabase) -> Cancelable<Option<Module>> {
|
|
||||||
let crate_graph = db.crate_graph();
|
|
||||||
let file_id = crate_graph.crate_root(self.crate_id);
|
|
||||||
let source_root_id = db.file_source_root(file_id);
|
|
||||||
let file_id = HirFileId::from(file_id);
|
|
||||||
let module_tree = db.module_tree(source_root_id)?;
|
|
||||||
// FIXME: teach module tree about crate roots instead of guessing
|
|
||||||
let (module_id, _) = ctry!(module_tree
|
|
||||||
.modules_with_sources()
|
|
||||||
.find(|(_, src)| src.file_id() == file_id));
|
|
||||||
|
|
||||||
let def_loc = DefLoc {
|
|
||||||
kind: DefKind::Module,
|
|
||||||
source_root_id,
|
|
||||||
module_id,
|
|
||||||
source_item_id: module_id.source(&module_tree).0,
|
|
||||||
};
|
|
||||||
let def_id = def_loc.id(db);
|
|
||||||
|
|
||||||
let module = Module::new(def_id);
|
|
||||||
Ok(Some(module))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Module {
|
|
||||||
pub(crate) fn new(def_id: DefId) -> Self {
|
|
||||||
crate::code_model_api::Module { def_id }
|
|
||||||
}
|
|
||||||
pub(crate) fn from_module_id(
|
|
||||||
db: &impl HirDatabase,
|
|
||||||
source_root_id: SourceRootId,
|
|
||||||
module_id: ModuleId,
|
|
||||||
) -> Cancelable<Self> {
|
|
||||||
let module_tree = db.module_tree(source_root_id)?;
|
|
||||||
let def_loc = DefLoc {
|
|
||||||
kind: DefKind::Module,
|
|
||||||
source_root_id,
|
|
||||||
module_id,
|
|
||||||
source_item_id: module_id.source(&module_tree).0,
|
|
||||||
};
|
|
||||||
let def_id = def_loc.id(db);
|
|
||||||
let module = Module::new(def_id);
|
|
||||||
Ok(module)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn name_impl(&self, db: &impl HirDatabase) -> Cancelable<Option<Name>> {
|
|
||||||
let loc = self.def_id.loc(db);
|
|
||||||
let module_tree = db.module_tree(loc.source_root_id)?;
|
|
||||||
let link = ctry!(loc.module_id.parent_link(&module_tree));
|
|
||||||
Ok(Some(link.name(&module_tree).clone()))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn defenition_source_impl(
|
|
||||||
&self,
|
|
||||||
db: &impl HirDatabase,
|
|
||||||
) -> Cancelable<(FileId, ModuleSource)> {
|
|
||||||
let loc = self.def_id.loc(db);
|
|
||||||
let file_id = loc.source_item_id.file_id.as_original_file();
|
|
||||||
let syntax_node = db.file_item(loc.source_item_id);
|
|
||||||
let syntax_node = syntax_node.borrowed();
|
|
||||||
let module_source = if let Some(source_file) = ast::SourceFile::cast(syntax_node) {
|
|
||||||
ModuleSource::SourceFile(source_file.owned())
|
|
||||||
} else {
|
|
||||||
let module = ast::Module::cast(syntax_node).unwrap();
|
|
||||||
ModuleSource::Module(module.owned())
|
|
||||||
};
|
|
||||||
Ok((file_id, module_source))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn declaration_source_impl(
|
|
||||||
&self,
|
|
||||||
db: &impl HirDatabase,
|
|
||||||
) -> Cancelable<Option<(FileId, ast::ModuleNode)>> {
|
|
||||||
let loc = self.def_id.loc(db);
|
|
||||||
let module_tree = db.module_tree(loc.source_root_id)?;
|
|
||||||
let link = ctry!(loc.module_id.parent_link(&module_tree));
|
|
||||||
let file_id = link
|
|
||||||
.owner(&module_tree)
|
|
||||||
.source(&module_tree)
|
|
||||||
.file_id()
|
|
||||||
.as_original_file();
|
|
||||||
let src = link.bind_source(&module_tree, db);
|
|
||||||
Ok(Some((file_id, src)))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn krate_impl(&self, db: &impl HirDatabase) -> Cancelable<Option<Crate>> {
|
|
||||||
let root = self.crate_root(db)?;
|
|
||||||
let loc = root.def_id.loc(db);
|
|
||||||
let file_id = loc.source_item_id.file_id.as_original_file();
|
|
||||||
|
|
||||||
let crate_graph = db.crate_graph();
|
|
||||||
let crate_id = ctry!(crate_graph.crate_id_for_crate_root(file_id));
|
|
||||||
Ok(Some(Crate::new(crate_id)))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn crate_root_impl(&self, db: &impl HirDatabase) -> Cancelable<Module> {
|
|
||||||
let loc = self.def_id.loc(db);
|
|
||||||
let module_tree = db.module_tree(loc.source_root_id)?;
|
|
||||||
let module_id = loc.module_id.crate_root(&module_tree);
|
|
||||||
Module::from_module_id(db, loc.source_root_id, module_id)
|
|
||||||
}
|
|
||||||
/// Finds a child module with the specified name.
|
|
||||||
pub fn child_impl(&self, db: &impl HirDatabase, name: &Name) -> Cancelable<Option<Module>> {
|
|
||||||
let loc = self.def_id.loc(db);
|
|
||||||
let module_tree = db.module_tree(loc.source_root_id)?;
|
|
||||||
let child_id = ctry!(loc.module_id.child(&module_tree, name));
|
|
||||||
Module::from_module_id(db, loc.source_root_id, child_id).map(Some)
|
|
||||||
}
|
|
||||||
pub fn parent_impl(&self, db: &impl HirDatabase) -> Cancelable<Option<Module>> {
|
|
||||||
let loc = self.def_id.loc(db);
|
|
||||||
let module_tree = db.module_tree(loc.source_root_id)?;
|
|
||||||
let parent_id = ctry!(loc.module_id.parent(&module_tree));
|
|
||||||
Module::from_module_id(db, loc.source_root_id, parent_id).map(Some)
|
|
||||||
}
|
|
||||||
/// Returns a `ModuleScope`: a set of items, visible in this module.
|
|
||||||
pub fn scope_impl(&self, db: &impl HirDatabase) -> Cancelable<ModuleScope> {
|
|
||||||
let loc = self.def_id.loc(db);
|
|
||||||
let item_map = db.item_map(loc.source_root_id)?;
|
|
||||||
let res = item_map.per_module[&loc.module_id].clone();
|
|
||||||
Ok(res)
|
|
||||||
}
|
|
||||||
pub fn resolve_path_impl(
|
|
||||||
&self,
|
|
||||||
db: &impl HirDatabase,
|
|
||||||
path: &Path,
|
|
||||||
) -> Cancelable<PerNs<DefId>> {
|
|
||||||
let mut curr_per_ns = PerNs::types(
|
|
||||||
match path.kind {
|
|
||||||
PathKind::Crate => self.crate_root(db)?,
|
|
||||||
PathKind::Self_ | PathKind::Plain => self.clone(),
|
|
||||||
PathKind::Super => {
|
|
||||||
if let Some(p) = self.parent(db)? {
|
|
||||||
p
|
|
||||||
} else {
|
|
||||||
return Ok(PerNs::none());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.def_id,
|
|
||||||
);
|
|
||||||
|
|
||||||
let segments = &path.segments;
|
|
||||||
for name in segments.iter() {
|
|
||||||
let curr = if let Some(r) = curr_per_ns.as_ref().take_types() {
|
|
||||||
r
|
|
||||||
} else {
|
|
||||||
return Ok(PerNs::none());
|
|
||||||
};
|
|
||||||
let module = match curr.resolve(db)? {
|
|
||||||
Def::Module(it) => it,
|
|
||||||
// TODO here would be the place to handle enum variants...
|
|
||||||
_ => return Ok(PerNs::none()),
|
|
||||||
};
|
|
||||||
let scope = module.scope(db)?;
|
|
||||||
curr_per_ns = if let Some(r) = scope.get(&name) {
|
|
||||||
r.def_id
|
|
||||||
} else {
|
|
||||||
return Ok(PerNs::none());
|
|
||||||
};
|
|
||||||
}
|
|
||||||
Ok(curr_per_ns)
|
|
||||||
}
|
|
||||||
pub fn problems_impl(&self, db: &impl HirDatabase) -> Cancelable<Vec<(SyntaxNode, Problem)>> {
|
|
||||||
let loc = self.def_id.loc(db);
|
|
||||||
let module_tree = db.module_tree(loc.source_root_id)?;
|
|
||||||
Ok(loc.module_id.problems(&module_tree, db))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
45
crates/ra_hir/src/code_model_impl/krate.rs
Normal file
45
crates/ra_hir/src/code_model_impl/krate.rs
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
use ra_db::{CrateId, Cancelable};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
HirFileId, Crate, CrateDependency, AsName, DefLoc, DefKind, Module,
|
||||||
|
db::HirDatabase,
|
||||||
|
};
|
||||||
|
|
||||||
|
impl Crate {
|
||||||
|
pub(crate) fn new(crate_id: CrateId) -> Crate {
|
||||||
|
Crate { crate_id }
|
||||||
|
}
|
||||||
|
pub(crate) fn dependencies_impl(&self, db: &impl HirDatabase) -> Vec<CrateDependency> {
|
||||||
|
let crate_graph = db.crate_graph();
|
||||||
|
crate_graph
|
||||||
|
.dependencies(self.crate_id)
|
||||||
|
.map(|dep| {
|
||||||
|
let krate = Crate::new(dep.crate_id());
|
||||||
|
let name = dep.as_name();
|
||||||
|
CrateDependency { krate, name }
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
pub(crate) fn root_module_impl(&self, db: &impl HirDatabase) -> Cancelable<Option<Module>> {
|
||||||
|
let crate_graph = db.crate_graph();
|
||||||
|
let file_id = crate_graph.crate_root(self.crate_id);
|
||||||
|
let source_root_id = db.file_source_root(file_id);
|
||||||
|
let file_id = HirFileId::from(file_id);
|
||||||
|
let module_tree = db.module_tree(source_root_id)?;
|
||||||
|
// FIXME: teach module tree about crate roots instead of guessing
|
||||||
|
let (module_id, _) = ctry!(module_tree
|
||||||
|
.modules_with_sources()
|
||||||
|
.find(|(_, src)| src.file_id() == file_id));
|
||||||
|
|
||||||
|
let def_loc = DefLoc {
|
||||||
|
kind: DefKind::Module,
|
||||||
|
source_root_id,
|
||||||
|
module_id,
|
||||||
|
source_item_id: module_id.source(&module_tree).0,
|
||||||
|
};
|
||||||
|
let def_id = def_loc.id(db);
|
||||||
|
|
||||||
|
let module = Module::new(def_id);
|
||||||
|
Ok(Some(module))
|
||||||
|
}
|
||||||
|
}
|
154
crates/ra_hir/src/code_model_impl/module.rs
Normal file
154
crates/ra_hir/src/code_model_impl/module.rs
Normal file
|
@ -0,0 +1,154 @@
|
||||||
|
use ra_db::{Cancelable, SourceRootId, FileId};
|
||||||
|
use ra_syntax::{ast, SyntaxNode, AstNode};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
Module, ModuleSource, Problem,
|
||||||
|
Crate, DefId, DefLoc, DefKind, Name, Path, PathKind, PerNs, Def, ModuleId,
|
||||||
|
nameres::ModuleScope,
|
||||||
|
db::HirDatabase,
|
||||||
|
};
|
||||||
|
|
||||||
|
impl Module {
|
||||||
|
pub(crate) fn new(def_id: DefId) -> Self {
|
||||||
|
crate::code_model_api::Module { def_id }
|
||||||
|
}
|
||||||
|
pub(crate) fn from_module_id(
|
||||||
|
db: &impl HirDatabase,
|
||||||
|
source_root_id: SourceRootId,
|
||||||
|
module_id: ModuleId,
|
||||||
|
) -> Cancelable<Self> {
|
||||||
|
let module_tree = db.module_tree(source_root_id)?;
|
||||||
|
let def_loc = DefLoc {
|
||||||
|
kind: DefKind::Module,
|
||||||
|
source_root_id,
|
||||||
|
module_id,
|
||||||
|
source_item_id: module_id.source(&module_tree).0,
|
||||||
|
};
|
||||||
|
let def_id = def_loc.id(db);
|
||||||
|
let module = Module::new(def_id);
|
||||||
|
Ok(module)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn name_impl(&self, db: &impl HirDatabase) -> Cancelable<Option<Name>> {
|
||||||
|
let loc = self.def_id.loc(db);
|
||||||
|
let module_tree = db.module_tree(loc.source_root_id)?;
|
||||||
|
let link = ctry!(loc.module_id.parent_link(&module_tree));
|
||||||
|
Ok(Some(link.name(&module_tree).clone()))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn defenition_source_impl(
|
||||||
|
&self,
|
||||||
|
db: &impl HirDatabase,
|
||||||
|
) -> Cancelable<(FileId, ModuleSource)> {
|
||||||
|
let loc = self.def_id.loc(db);
|
||||||
|
let file_id = loc.source_item_id.file_id.as_original_file();
|
||||||
|
let syntax_node = db.file_item(loc.source_item_id);
|
||||||
|
let syntax_node = syntax_node.borrowed();
|
||||||
|
let module_source = if let Some(source_file) = ast::SourceFile::cast(syntax_node) {
|
||||||
|
ModuleSource::SourceFile(source_file.owned())
|
||||||
|
} else {
|
||||||
|
let module = ast::Module::cast(syntax_node).unwrap();
|
||||||
|
ModuleSource::Module(module.owned())
|
||||||
|
};
|
||||||
|
Ok((file_id, module_source))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn declaration_source_impl(
|
||||||
|
&self,
|
||||||
|
db: &impl HirDatabase,
|
||||||
|
) -> Cancelable<Option<(FileId, ast::ModuleNode)>> {
|
||||||
|
let loc = self.def_id.loc(db);
|
||||||
|
let module_tree = db.module_tree(loc.source_root_id)?;
|
||||||
|
let link = ctry!(loc.module_id.parent_link(&module_tree));
|
||||||
|
let file_id = link
|
||||||
|
.owner(&module_tree)
|
||||||
|
.source(&module_tree)
|
||||||
|
.file_id()
|
||||||
|
.as_original_file();
|
||||||
|
let src = link.bind_source(&module_tree, db);
|
||||||
|
Ok(Some((file_id, src)))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn krate_impl(&self, db: &impl HirDatabase) -> Cancelable<Option<Crate>> {
|
||||||
|
let root = self.crate_root(db)?;
|
||||||
|
let loc = root.def_id.loc(db);
|
||||||
|
let file_id = loc.source_item_id.file_id.as_original_file();
|
||||||
|
|
||||||
|
let crate_graph = db.crate_graph();
|
||||||
|
let crate_id = ctry!(crate_graph.crate_id_for_crate_root(file_id));
|
||||||
|
Ok(Some(Crate::new(crate_id)))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn crate_root_impl(&self, db: &impl HirDatabase) -> Cancelable<Module> {
|
||||||
|
let loc = self.def_id.loc(db);
|
||||||
|
let module_tree = db.module_tree(loc.source_root_id)?;
|
||||||
|
let module_id = loc.module_id.crate_root(&module_tree);
|
||||||
|
Module::from_module_id(db, loc.source_root_id, module_id)
|
||||||
|
}
|
||||||
|
/// Finds a child module with the specified name.
|
||||||
|
pub fn child_impl(&self, db: &impl HirDatabase, name: &Name) -> Cancelable<Option<Module>> {
|
||||||
|
let loc = self.def_id.loc(db);
|
||||||
|
let module_tree = db.module_tree(loc.source_root_id)?;
|
||||||
|
let child_id = ctry!(loc.module_id.child(&module_tree, name));
|
||||||
|
Module::from_module_id(db, loc.source_root_id, child_id).map(Some)
|
||||||
|
}
|
||||||
|
pub fn parent_impl(&self, db: &impl HirDatabase) -> Cancelable<Option<Module>> {
|
||||||
|
let loc = self.def_id.loc(db);
|
||||||
|
let module_tree = db.module_tree(loc.source_root_id)?;
|
||||||
|
let parent_id = ctry!(loc.module_id.parent(&module_tree));
|
||||||
|
Module::from_module_id(db, loc.source_root_id, parent_id).map(Some)
|
||||||
|
}
|
||||||
|
/// Returns a `ModuleScope`: a set of items, visible in this module.
|
||||||
|
pub fn scope_impl(&self, db: &impl HirDatabase) -> Cancelable<ModuleScope> {
|
||||||
|
let loc = self.def_id.loc(db);
|
||||||
|
let item_map = db.item_map(loc.source_root_id)?;
|
||||||
|
let res = item_map.per_module[&loc.module_id].clone();
|
||||||
|
Ok(res)
|
||||||
|
}
|
||||||
|
pub fn resolve_path_impl(
|
||||||
|
&self,
|
||||||
|
db: &impl HirDatabase,
|
||||||
|
path: &Path,
|
||||||
|
) -> Cancelable<PerNs<DefId>> {
|
||||||
|
let mut curr_per_ns = PerNs::types(
|
||||||
|
match path.kind {
|
||||||
|
PathKind::Crate => self.crate_root(db)?,
|
||||||
|
PathKind::Self_ | PathKind::Plain => self.clone(),
|
||||||
|
PathKind::Super => {
|
||||||
|
if let Some(p) = self.parent(db)? {
|
||||||
|
p
|
||||||
|
} else {
|
||||||
|
return Ok(PerNs::none());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.def_id,
|
||||||
|
);
|
||||||
|
|
||||||
|
let segments = &path.segments;
|
||||||
|
for name in segments.iter() {
|
||||||
|
let curr = if let Some(r) = curr_per_ns.as_ref().take_types() {
|
||||||
|
r
|
||||||
|
} else {
|
||||||
|
return Ok(PerNs::none());
|
||||||
|
};
|
||||||
|
let module = match curr.resolve(db)? {
|
||||||
|
Def::Module(it) => it,
|
||||||
|
// TODO here would be the place to handle enum variants...
|
||||||
|
_ => return Ok(PerNs::none()),
|
||||||
|
};
|
||||||
|
let scope = module.scope(db)?;
|
||||||
|
curr_per_ns = if let Some(r) = scope.get(&name) {
|
||||||
|
r.def_id
|
||||||
|
} else {
|
||||||
|
return Ok(PerNs::none());
|
||||||
|
};
|
||||||
|
}
|
||||||
|
Ok(curr_per_ns)
|
||||||
|
}
|
||||||
|
pub fn problems_impl(&self, db: &impl HirDatabase) -> Cancelable<Vec<(SyntaxNode, Problem)>> {
|
||||||
|
let loc = self.def_id.loc(db);
|
||||||
|
let module_tree = db.module_tree(loc.source_root_id)?;
|
||||||
|
Ok(loc.module_id.problems(&module_tree, db))
|
||||||
|
}
|
||||||
|
}
|
|
@ -9,8 +9,8 @@ use crate::{
|
||||||
query_definitions,
|
query_definitions,
|
||||||
FnSignature, FnScopes,
|
FnSignature, FnScopes,
|
||||||
macros::MacroExpansion,
|
macros::MacroExpansion,
|
||||||
module::{ModuleId, ModuleTree, ModuleSource,
|
module_tree::{ModuleId, ModuleTree, ModuleSource},
|
||||||
nameres::{ItemMap, InputModuleItems}},
|
nameres::{ItemMap, InputModuleItems},
|
||||||
ty::{InferenceResult, Ty},
|
ty::{InferenceResult, Ty},
|
||||||
adt::{StructData, EnumData},
|
adt::{StructData, EnumData},
|
||||||
impl_block::ModuleImplBlocks,
|
impl_block::ModuleImplBlocks,
|
||||||
|
@ -71,7 +71,7 @@ pub trait HirDatabase: SyntaxDatabase
|
||||||
use fn query_definitions::file_item;
|
use fn query_definitions::file_item;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn submodules(source: ModuleSource) -> Cancelable<Arc<Vec<crate::module::imp::Submodule>>> {
|
fn submodules(source: ModuleSource) -> Cancelable<Arc<Vec<crate::module_tree::Submodule>>> {
|
||||||
type SubmodulesQuery;
|
type SubmodulesQuery;
|
||||||
use fn query_definitions::submodules;
|
use fn query_definitions::submodules;
|
||||||
}
|
}
|
||||||
|
@ -86,7 +86,7 @@ pub trait HirDatabase: SyntaxDatabase
|
||||||
}
|
}
|
||||||
fn module_tree(source_root_id: SourceRootId) -> Cancelable<Arc<ModuleTree>> {
|
fn module_tree(source_root_id: SourceRootId) -> Cancelable<Arc<ModuleTree>> {
|
||||||
type ModuleTreeQuery;
|
type ModuleTreeQuery;
|
||||||
use fn crate::module::imp::module_tree;
|
use fn crate::module_tree::ModuleTree::module_tree_query;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn impls_in_module(source_root_id: SourceRootId, module_id: ModuleId) -> Cancelable<Arc<ModuleImplBlocks>> {
|
fn impls_in_module(source_root_id: SourceRootId, module_id: ModuleId) -> Cancelable<Arc<ModuleImplBlocks>> {
|
||||||
|
|
|
@ -10,7 +10,7 @@ use crate::{
|
||||||
Function,
|
Function,
|
||||||
db::HirDatabase,
|
db::HirDatabase,
|
||||||
type_ref::TypeRef,
|
type_ref::TypeRef,
|
||||||
module::ModuleId,
|
module_tree::ModuleId,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::code_model_api::{Module, ModuleSource};
|
use crate::code_model_api::{Module, ModuleSource};
|
||||||
|
|
|
@ -24,7 +24,8 @@ pub mod source_binder;
|
||||||
mod ids;
|
mod ids;
|
||||||
mod macros;
|
mod macros;
|
||||||
mod name;
|
mod name;
|
||||||
mod module;
|
mod module_tree;
|
||||||
|
mod nameres;
|
||||||
mod function;
|
mod function;
|
||||||
mod adt;
|
mod adt;
|
||||||
mod type_ref;
|
mod type_ref;
|
||||||
|
@ -32,14 +33,13 @@ mod ty;
|
||||||
mod impl_block;
|
mod impl_block;
|
||||||
mod expr;
|
mod expr;
|
||||||
|
|
||||||
pub mod code_model_api;
|
mod code_model_api;
|
||||||
mod code_model_impl;
|
mod code_model_impl;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
db::HirDatabase,
|
db::HirDatabase,
|
||||||
name::{AsName, KnownName},
|
name::{AsName, KnownName},
|
||||||
ids::{DefKind, SourceItemId, SourceFileItemId, SourceFileItems},
|
ids::{DefKind, SourceItemId, SourceFileItemId, SourceFileItems},
|
||||||
code_model_api::{Crate, CrateDependency}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
pub use self::{
|
pub use self::{
|
||||||
|
@ -56,7 +56,10 @@ pub use self::{
|
||||||
|
|
||||||
pub use self::function::FnSignatureInfo;
|
pub use self::function::FnSignatureInfo;
|
||||||
|
|
||||||
pub use self::code_model_api::Module;
|
pub use self::code_model_api::{
|
||||||
|
Crate, CrateDependency,
|
||||||
|
Module, ModuleSource, Problem,
|
||||||
|
};
|
||||||
|
|
||||||
pub enum Def {
|
pub enum Def {
|
||||||
Module(Module),
|
Module(Module),
|
||||||
|
|
|
@ -1,190 +0,0 @@
|
||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
use ra_syntax::ast::{self, NameOwner};
|
|
||||||
use relative_path::RelativePathBuf;
|
|
||||||
use rustc_hash::{FxHashMap, FxHashSet};
|
|
||||||
use arrayvec::ArrayVec;
|
|
||||||
use ra_db::{SourceRoot, SourceRootId, Cancelable, FileId};
|
|
||||||
|
|
||||||
use crate::{
|
|
||||||
HirDatabase, Name, AsName,
|
|
||||||
};
|
|
||||||
|
|
||||||
use super::{
|
|
||||||
LinkData, LinkId, ModuleData, ModuleId, ModuleSource,
|
|
||||||
ModuleTree, Problem,
|
|
||||||
};
|
|
||||||
|
|
||||||
#[derive(Clone, Hash, PartialEq, Eq, Debug)]
|
|
||||||
pub enum Submodule {
|
|
||||||
Declaration(Name),
|
|
||||||
Definition(Name, ModuleSource),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Submodule {
|
|
||||||
fn name(&self) -> &Name {
|
|
||||||
match self {
|
|
||||||
Submodule::Declaration(name) => name,
|
|
||||||
Submodule::Definition(name, _) => name,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn modules<'a>(
|
|
||||||
root: impl ast::ModuleItemOwner<'a>,
|
|
||||||
) -> impl Iterator<Item = (Name, ast::Module<'a>)> {
|
|
||||||
root.items()
|
|
||||||
.filter_map(|item| match item {
|
|
||||||
ast::ModuleItem::Module(m) => Some(m),
|
|
||||||
_ => None,
|
|
||||||
})
|
|
||||||
.filter_map(|module| {
|
|
||||||
let name = module.name()?.as_name();
|
|
||||||
Some((name, module))
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn module_tree(
|
|
||||||
db: &impl HirDatabase,
|
|
||||||
source_root: SourceRootId,
|
|
||||||
) -> Cancelable<Arc<ModuleTree>> {
|
|
||||||
db.check_canceled()?;
|
|
||||||
let res = create_module_tree(db, source_root)?;
|
|
||||||
Ok(Arc::new(res))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn create_module_tree<'a>(
|
|
||||||
db: &impl HirDatabase,
|
|
||||||
source_root: SourceRootId,
|
|
||||||
) -> Cancelable<ModuleTree> {
|
|
||||||
let mut tree = ModuleTree::default();
|
|
||||||
|
|
||||||
let mut roots = FxHashMap::default();
|
|
||||||
let mut visited = FxHashSet::default();
|
|
||||||
|
|
||||||
let source_root = db.source_root(source_root);
|
|
||||||
for &file_id in source_root.files.values() {
|
|
||||||
let source = ModuleSource::new_file(file_id.into());
|
|
||||||
if visited.contains(&source) {
|
|
||||||
continue; // TODO: use explicit crate_roots here
|
|
||||||
}
|
|
||||||
assert!(!roots.contains_key(&file_id));
|
|
||||||
let module_id = build_subtree(
|
|
||||||
db,
|
|
||||||
&source_root,
|
|
||||||
&mut tree,
|
|
||||||
&mut visited,
|
|
||||||
&mut roots,
|
|
||||||
None,
|
|
||||||
source,
|
|
||||||
)?;
|
|
||||||
roots.insert(file_id, module_id);
|
|
||||||
}
|
|
||||||
Ok(tree)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn build_subtree(
|
|
||||||
db: &impl HirDatabase,
|
|
||||||
source_root: &SourceRoot,
|
|
||||||
tree: &mut ModuleTree,
|
|
||||||
visited: &mut FxHashSet<ModuleSource>,
|
|
||||||
roots: &mut FxHashMap<FileId, ModuleId>,
|
|
||||||
parent: Option<LinkId>,
|
|
||||||
source: ModuleSource,
|
|
||||||
) -> Cancelable<ModuleId> {
|
|
||||||
visited.insert(source);
|
|
||||||
let id = tree.push_mod(ModuleData {
|
|
||||||
source,
|
|
||||||
parent,
|
|
||||||
children: Vec::new(),
|
|
||||||
});
|
|
||||||
for sub in db.submodules(source)?.iter() {
|
|
||||||
let link = tree.push_link(LinkData {
|
|
||||||
name: sub.name().clone(),
|
|
||||||
owner: id,
|
|
||||||
points_to: Vec::new(),
|
|
||||||
problem: None,
|
|
||||||
});
|
|
||||||
|
|
||||||
let (points_to, problem) = match sub {
|
|
||||||
Submodule::Declaration(name) => {
|
|
||||||
let (points_to, problem) = resolve_submodule(db, source, &name);
|
|
||||||
let points_to = points_to
|
|
||||||
.into_iter()
|
|
||||||
.map(|file_id| match roots.remove(&file_id) {
|
|
||||||
Some(module_id) => {
|
|
||||||
tree.mods[module_id].parent = Some(link);
|
|
||||||
Ok(module_id)
|
|
||||||
}
|
|
||||||
None => build_subtree(
|
|
||||||
db,
|
|
||||||
source_root,
|
|
||||||
tree,
|
|
||||||
visited,
|
|
||||||
roots,
|
|
||||||
Some(link),
|
|
||||||
ModuleSource::new_file(file_id.into()),
|
|
||||||
),
|
|
||||||
})
|
|
||||||
.collect::<Cancelable<Vec<_>>>()?;
|
|
||||||
(points_to, problem)
|
|
||||||
}
|
|
||||||
Submodule::Definition(_name, submodule_source) => {
|
|
||||||
let points_to = build_subtree(
|
|
||||||
db,
|
|
||||||
source_root,
|
|
||||||
tree,
|
|
||||||
visited,
|
|
||||||
roots,
|
|
||||||
Some(link),
|
|
||||||
*submodule_source,
|
|
||||||
)?;
|
|
||||||
(vec![points_to], None)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
tree.links[link].points_to = points_to;
|
|
||||||
tree.links[link].problem = problem;
|
|
||||||
}
|
|
||||||
Ok(id)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn resolve_submodule(
|
|
||||||
db: &impl HirDatabase,
|
|
||||||
source: ModuleSource,
|
|
||||||
name: &Name,
|
|
||||||
) -> (Vec<FileId>, Option<Problem>) {
|
|
||||||
// FIXME: handle submodules of inline modules properly
|
|
||||||
let file_id = source.file_id().original_file(db);
|
|
||||||
let source_root_id = db.file_source_root(file_id);
|
|
||||||
let path = db.file_relative_path(file_id);
|
|
||||||
let root = RelativePathBuf::default();
|
|
||||||
let dir_path = path.parent().unwrap_or(&root);
|
|
||||||
let mod_name = path.file_stem().unwrap_or("unknown");
|
|
||||||
let is_dir_owner = mod_name == "mod" || mod_name == "lib" || mod_name == "main";
|
|
||||||
|
|
||||||
let file_mod = dir_path.join(format!("{}.rs", name));
|
|
||||||
let dir_mod = dir_path.join(format!("{}/mod.rs", name));
|
|
||||||
let file_dir_mod = dir_path.join(format!("{}/{}.rs", mod_name, name));
|
|
||||||
let mut candidates = ArrayVec::<[_; 2]>::new();
|
|
||||||
if is_dir_owner {
|
|
||||||
candidates.push(file_mod.clone());
|
|
||||||
candidates.push(dir_mod);
|
|
||||||
} else {
|
|
||||||
candidates.push(file_dir_mod.clone());
|
|
||||||
};
|
|
||||||
let sr = db.source_root(source_root_id);
|
|
||||||
let points_to = candidates
|
|
||||||
.into_iter()
|
|
||||||
.filter_map(|path| sr.files.get(&path))
|
|
||||||
.map(|&it| it)
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
let problem = if points_to.is_empty() {
|
|
||||||
Some(Problem::UnresolvedModule {
|
|
||||||
candidate: if is_dir_owner { file_mod } else { file_dir_mod },
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
(points_to, problem)
|
|
||||||
}
|
|
|
@ -1,17 +1,32 @@
|
||||||
pub(super) mod imp;
|
use std::sync::Arc;
|
||||||
pub(super) mod nameres;
|
|
||||||
|
|
||||||
|
use rustc_hash::{FxHashMap, FxHashSet};
|
||||||
|
use arrayvec::ArrayVec;
|
||||||
|
use relative_path::RelativePathBuf;
|
||||||
|
use ra_db::{FileId, SourceRootId, Cancelable, SourceRoot};
|
||||||
use ra_syntax::{
|
use ra_syntax::{
|
||||||
algo::generate,
|
algo::generate,
|
||||||
ast::{self, AstNode, NameOwner},
|
ast::{self, AstNode, NameOwner},
|
||||||
SyntaxNode,
|
SyntaxNode,
|
||||||
};
|
};
|
||||||
use ra_arena::{Arena, RawId, impl_arena_id};
|
use ra_arena::{Arena, RawId, impl_arena_id};
|
||||||
use relative_path::RelativePathBuf;
|
|
||||||
|
|
||||||
use crate::{Name, HirDatabase, SourceItemId, SourceFileItemId, HirFileId};
|
use crate::{Name, AsName, HirDatabase, SourceItemId, SourceFileItemId, HirFileId, Problem};
|
||||||
|
|
||||||
pub use self::nameres::{ModuleScope, Resolution, Namespace, PerNs};
|
#[derive(Clone, Hash, PartialEq, Eq, Debug)]
|
||||||
|
pub enum Submodule {
|
||||||
|
Declaration(Name),
|
||||||
|
Definition(Name, ModuleSource),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Submodule {
|
||||||
|
fn name(&self) -> &Name {
|
||||||
|
match self {
|
||||||
|
Submodule::Declaration(name) => name,
|
||||||
|
Submodule::Definition(name, _) => name,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
pub struct ModuleId(RawId);
|
pub struct ModuleId(RawId);
|
||||||
|
@ -34,7 +49,31 @@ pub struct ModuleTree {
|
||||||
links: Arena<LinkId, LinkData>,
|
links: Arena<LinkId, LinkData>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq, Hash)]
|
||||||
|
pub struct ModuleData {
|
||||||
|
source: ModuleSource,
|
||||||
|
parent: Option<LinkId>,
|
||||||
|
children: Vec<LinkId>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Hash, Debug, PartialEq, Eq)]
|
||||||
|
struct LinkData {
|
||||||
|
owner: ModuleId,
|
||||||
|
name: Name,
|
||||||
|
points_to: Vec<ModuleId>,
|
||||||
|
problem: Option<Problem>,
|
||||||
|
}
|
||||||
|
|
||||||
impl ModuleTree {
|
impl ModuleTree {
|
||||||
|
pub(crate) fn module_tree_query(
|
||||||
|
db: &impl HirDatabase,
|
||||||
|
source_root: SourceRootId,
|
||||||
|
) -> Cancelable<Arc<ModuleTree>> {
|
||||||
|
db.check_canceled()?;
|
||||||
|
let res = create_module_tree(db, source_root)?;
|
||||||
|
Ok(Arc::new(res))
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn modules<'a>(&'a self) -> impl Iterator<Item = ModuleId> + 'a {
|
pub(crate) fn modules<'a>(&'a self) -> impl Iterator<Item = ModuleId> + 'a {
|
||||||
self.mods.iter().map(|(id, _)| id)
|
self.mods.iter().map(|(id, _)| id)
|
||||||
}
|
}
|
||||||
|
@ -58,17 +97,6 @@ pub(crate) enum ModuleSourceNode {
|
||||||
Module(ast::ModuleNode),
|
Module(ast::ModuleNode),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
|
|
||||||
pub enum Problem {
|
|
||||||
UnresolvedModule {
|
|
||||||
candidate: RelativePathBuf,
|
|
||||||
},
|
|
||||||
NotDirOwner {
|
|
||||||
move_to: RelativePathBuf,
|
|
||||||
candidate: RelativePathBuf,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ModuleId {
|
impl ModuleId {
|
||||||
pub(crate) fn source(self, tree: &ModuleTree) -> ModuleSource {
|
pub(crate) fn source(self, tree: &ModuleTree) -> ModuleSource {
|
||||||
tree.mods[self].source
|
tree.mods[self].source
|
||||||
|
@ -93,7 +121,10 @@ impl ModuleId {
|
||||||
.find(|it| it.name == *name)?;
|
.find(|it| it.name == *name)?;
|
||||||
Some(*link.points_to.first()?)
|
Some(*link.points_to.first()?)
|
||||||
}
|
}
|
||||||
fn children<'a>(self, tree: &'a ModuleTree) -> impl Iterator<Item = (Name, ModuleId)> + 'a {
|
pub(crate) fn children<'a>(
|
||||||
|
self,
|
||||||
|
tree: &'a ModuleTree,
|
||||||
|
) -> impl Iterator<Item = (Name, ModuleId)> + 'a {
|
||||||
tree.mods[self].children.iter().filter_map(move |&it| {
|
tree.mods[self].children.iter().filter_map(move |&it| {
|
||||||
let link = &tree.links[it];
|
let link = &tree.links[it];
|
||||||
let module = *link.points_to.first()?;
|
let module = *link.points_to.first()?;
|
||||||
|
@ -133,7 +164,7 @@ impl LinkId {
|
||||||
let owner = self.owner(tree);
|
let owner = self.owner(tree);
|
||||||
match owner.source(tree).resolve(db) {
|
match owner.source(tree).resolve(db) {
|
||||||
ModuleSourceNode::SourceFile(root) => {
|
ModuleSourceNode::SourceFile(root) => {
|
||||||
let ast = imp::modules(root.borrowed())
|
let ast = modules(root.borrowed())
|
||||||
.find(|(name, _)| name == &tree.links[self].name)
|
.find(|(name, _)| name == &tree.links[self].name)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.1;
|
.1;
|
||||||
|
@ -144,13 +175,6 @@ impl LinkId {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq, Hash)]
|
|
||||||
pub struct ModuleData {
|
|
||||||
source: ModuleSource,
|
|
||||||
parent: Option<LinkId>,
|
|
||||||
children: Vec<LinkId>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ModuleSource {
|
impl ModuleSource {
|
||||||
// precondition: item_id **must** point to module
|
// precondition: item_id **must** point to module
|
||||||
fn new(file_id: HirFileId, item_id: Option<SourceFileItemId>) -> ModuleSource {
|
fn new(file_id: HirFileId, item_id: Option<SourceFileItemId>) -> ModuleSource {
|
||||||
|
@ -188,14 +212,6 @@ impl ModuleSource {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Hash, Debug, PartialEq, Eq)]
|
|
||||||
struct LinkData {
|
|
||||||
owner: ModuleId,
|
|
||||||
name: Name,
|
|
||||||
points_to: Vec<ModuleId>,
|
|
||||||
problem: Option<Problem>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ModuleTree {
|
impl ModuleTree {
|
||||||
fn push_mod(&mut self, data: ModuleData) -> ModuleId {
|
fn push_mod(&mut self, data: ModuleData) -> ModuleId {
|
||||||
self.mods.alloc(data)
|
self.mods.alloc(data)
|
||||||
|
@ -207,3 +223,153 @@ impl ModuleTree {
|
||||||
id
|
id
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn modules<'a>(
|
||||||
|
root: impl ast::ModuleItemOwner<'a>,
|
||||||
|
) -> impl Iterator<Item = (Name, ast::Module<'a>)> {
|
||||||
|
root.items()
|
||||||
|
.filter_map(|item| match item {
|
||||||
|
ast::ModuleItem::Module(m) => Some(m),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
.filter_map(|module| {
|
||||||
|
let name = module.name()?.as_name();
|
||||||
|
Some((name, module))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn create_module_tree<'a>(
|
||||||
|
db: &impl HirDatabase,
|
||||||
|
source_root: SourceRootId,
|
||||||
|
) -> Cancelable<ModuleTree> {
|
||||||
|
let mut tree = ModuleTree::default();
|
||||||
|
|
||||||
|
let mut roots = FxHashMap::default();
|
||||||
|
let mut visited = FxHashSet::default();
|
||||||
|
|
||||||
|
let source_root = db.source_root(source_root);
|
||||||
|
for &file_id in source_root.files.values() {
|
||||||
|
let source = ModuleSource::new_file(file_id.into());
|
||||||
|
if visited.contains(&source) {
|
||||||
|
continue; // TODO: use explicit crate_roots here
|
||||||
|
}
|
||||||
|
assert!(!roots.contains_key(&file_id));
|
||||||
|
let module_id = build_subtree(
|
||||||
|
db,
|
||||||
|
&source_root,
|
||||||
|
&mut tree,
|
||||||
|
&mut visited,
|
||||||
|
&mut roots,
|
||||||
|
None,
|
||||||
|
source,
|
||||||
|
)?;
|
||||||
|
roots.insert(file_id, module_id);
|
||||||
|
}
|
||||||
|
Ok(tree)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn build_subtree(
|
||||||
|
db: &impl HirDatabase,
|
||||||
|
source_root: &SourceRoot,
|
||||||
|
tree: &mut ModuleTree,
|
||||||
|
visited: &mut FxHashSet<ModuleSource>,
|
||||||
|
roots: &mut FxHashMap<FileId, ModuleId>,
|
||||||
|
parent: Option<LinkId>,
|
||||||
|
source: ModuleSource,
|
||||||
|
) -> Cancelable<ModuleId> {
|
||||||
|
visited.insert(source);
|
||||||
|
let id = tree.push_mod(ModuleData {
|
||||||
|
source,
|
||||||
|
parent,
|
||||||
|
children: Vec::new(),
|
||||||
|
});
|
||||||
|
for sub in db.submodules(source)?.iter() {
|
||||||
|
let link = tree.push_link(LinkData {
|
||||||
|
name: sub.name().clone(),
|
||||||
|
owner: id,
|
||||||
|
points_to: Vec::new(),
|
||||||
|
problem: None,
|
||||||
|
});
|
||||||
|
|
||||||
|
let (points_to, problem) = match sub {
|
||||||
|
Submodule::Declaration(name) => {
|
||||||
|
let (points_to, problem) = resolve_submodule(db, source, &name);
|
||||||
|
let points_to = points_to
|
||||||
|
.into_iter()
|
||||||
|
.map(|file_id| match roots.remove(&file_id) {
|
||||||
|
Some(module_id) => {
|
||||||
|
tree.mods[module_id].parent = Some(link);
|
||||||
|
Ok(module_id)
|
||||||
|
}
|
||||||
|
None => build_subtree(
|
||||||
|
db,
|
||||||
|
source_root,
|
||||||
|
tree,
|
||||||
|
visited,
|
||||||
|
roots,
|
||||||
|
Some(link),
|
||||||
|
ModuleSource::new_file(file_id.into()),
|
||||||
|
),
|
||||||
|
})
|
||||||
|
.collect::<Cancelable<Vec<_>>>()?;
|
||||||
|
(points_to, problem)
|
||||||
|
}
|
||||||
|
Submodule::Definition(_name, submodule_source) => {
|
||||||
|
let points_to = build_subtree(
|
||||||
|
db,
|
||||||
|
source_root,
|
||||||
|
tree,
|
||||||
|
visited,
|
||||||
|
roots,
|
||||||
|
Some(link),
|
||||||
|
*submodule_source,
|
||||||
|
)?;
|
||||||
|
(vec![points_to], None)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
tree.links[link].points_to = points_to;
|
||||||
|
tree.links[link].problem = problem;
|
||||||
|
}
|
||||||
|
Ok(id)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn resolve_submodule(
|
||||||
|
db: &impl HirDatabase,
|
||||||
|
source: ModuleSource,
|
||||||
|
name: &Name,
|
||||||
|
) -> (Vec<FileId>, Option<Problem>) {
|
||||||
|
// FIXME: handle submodules of inline modules properly
|
||||||
|
let file_id = source.file_id().original_file(db);
|
||||||
|
let source_root_id = db.file_source_root(file_id);
|
||||||
|
let path = db.file_relative_path(file_id);
|
||||||
|
let root = RelativePathBuf::default();
|
||||||
|
let dir_path = path.parent().unwrap_or(&root);
|
||||||
|
let mod_name = path.file_stem().unwrap_or("unknown");
|
||||||
|
let is_dir_owner = mod_name == "mod" || mod_name == "lib" || mod_name == "main";
|
||||||
|
|
||||||
|
let file_mod = dir_path.join(format!("{}.rs", name));
|
||||||
|
let dir_mod = dir_path.join(format!("{}/mod.rs", name));
|
||||||
|
let file_dir_mod = dir_path.join(format!("{}/{}.rs", mod_name, name));
|
||||||
|
let mut candidates = ArrayVec::<[_; 2]>::new();
|
||||||
|
if is_dir_owner {
|
||||||
|
candidates.push(file_mod.clone());
|
||||||
|
candidates.push(dir_mod);
|
||||||
|
} else {
|
||||||
|
candidates.push(file_dir_mod.clone());
|
||||||
|
};
|
||||||
|
let sr = db.source_root(source_root_id);
|
||||||
|
let points_to = candidates
|
||||||
|
.into_iter()
|
||||||
|
.filter_map(|path| sr.files.get(&path))
|
||||||
|
.map(|&it| it)
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
let problem = if points_to.is_empty() {
|
||||||
|
Some(Problem::UnresolvedModule {
|
||||||
|
candidate: if is_dir_owner { file_mod } else { file_dir_mod },
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
(points_to, problem)
|
||||||
|
}
|
|
@ -31,7 +31,7 @@ use crate::{
|
||||||
Path, PathKind,
|
Path, PathKind,
|
||||||
HirDatabase, Crate,
|
HirDatabase, Crate,
|
||||||
Name, AsName,
|
Name, AsName,
|
||||||
module::{ModuleId, ModuleTree},
|
module_tree::{ModuleId, ModuleTree},
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Item map is the result of the name resolution. Item map contains, for each
|
/// Item map is the result of the name resolution. Item map contains, for each
|
|
@ -17,7 +17,7 @@ fn item_map(fixture: &str) -> (Arc<hir::ItemMap>, hir::ModuleId) {
|
||||||
let module = hir::source_binder::module_from_position(&db, pos)
|
let module = hir::source_binder::module_from_position(&db, pos)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let module_id = module.def_id.loc(&db).module_id;
|
let module_id = module.module_id;
|
||||||
(db.item_map(source_root).unwrap(), module_id)
|
(db.item_map(source_root).unwrap(), module_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -155,7 +155,7 @@ fn item_map_across_crates() {
|
||||||
let module = hir::source_binder::module_from_file_id(&db, main_id)
|
let module = hir::source_binder::module_from_file_id(&db, main_id)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let module_id = module.def_id.loc(&db).module_id;
|
let module_id = module.module_id;
|
||||||
let item_map = db.item_map(source_root).unwrap();
|
let item_map = db.item_map(source_root).unwrap();
|
||||||
|
|
||||||
check_module_item_map(
|
check_module_item_map(
|
|
@ -15,11 +15,8 @@ use crate::{
|
||||||
MacroCallLoc,
|
MacroCallLoc,
|
||||||
db::HirDatabase,
|
db::HirDatabase,
|
||||||
function::FnScopes,
|
function::FnScopes,
|
||||||
module::{
|
module_tree::{ModuleId, Submodule, ModuleSource, ModuleSourceNode},
|
||||||
ModuleSource, ModuleSourceNode, ModuleId,
|
nameres::{InputModuleItems, ItemMap, Resolver},
|
||||||
imp::Submodule,
|
|
||||||
nameres::{InputModuleItems, ItemMap, Resolver},
|
|
||||||
},
|
|
||||||
adt::{StructData, EnumData},
|
adt::{StructData, EnumData},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,7 @@ use ra_syntax::{
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
HirDatabase, Function, SourceItemId,
|
HirDatabase, Function, SourceItemId,
|
||||||
module::ModuleSource,
|
module_tree::ModuleSource,
|
||||||
DefKind, DefLoc, AsName,
|
DefKind, DefLoc, AsName,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue