mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-11-10 23:24:29 +00:00
Merge #254
254: Defids r=matklad a=matklad Fleshing out DefIds some more Co-authored-by: Aleksey Kladov <aleksey.kladov@gmail.com>
This commit is contained in:
commit
84f2509730
12 changed files with 187 additions and 161 deletions
|
@ -163,7 +163,7 @@ fn complete_path(
|
||||||
};
|
};
|
||||||
let target_module = match def_id.resolve(db)? {
|
let target_module = match def_id.resolve(db)? {
|
||||||
Def::Module(it) => it,
|
Def::Module(it) => it,
|
||||||
Def::Item => return Ok(()),
|
_ => return Ok(()),
|
||||||
};
|
};
|
||||||
let module_scope = target_module.scope(db)?;
|
let module_scope = target_module.scope(db)?;
|
||||||
let completions = module_scope.entries().map(|(name, _res)| CompletionItem {
|
let completions = module_scope.entries().map(|(name, _res)| CompletionItem {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use salsa::{self, Database};
|
use salsa::{self, Database};
|
||||||
use ra_db::{LocationIntener, BaseDatabase};
|
use ra_db::{LocationIntener, BaseDatabase};
|
||||||
use hir::{self, DefId, DefLoc, FnId, SourceItemId};
|
use hir::{self, DefId, DefLoc};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
symbol_index,
|
symbol_index,
|
||||||
|
@ -15,7 +15,6 @@ pub(crate) struct RootDatabase {
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
struct IdMaps {
|
struct IdMaps {
|
||||||
fns: LocationIntener<SourceItemId, FnId>,
|
|
||||||
defs: LocationIntener<DefLoc, DefId>,
|
defs: LocationIntener<DefLoc, DefId>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,12 +57,6 @@ impl AsRef<LocationIntener<DefLoc, DefId>> for RootDatabase {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AsRef<LocationIntener<hir::SourceItemId, FnId>> for RootDatabase {
|
|
||||||
fn as_ref(&self) -> &LocationIntener<hir::SourceItemId, FnId> {
|
|
||||||
&self.id_maps.fns
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
salsa::database_storage! {
|
salsa::database_storage! {
|
||||||
pub(crate) struct RootDatabaseStorage for RootDatabase {
|
pub(crate) struct RootDatabaseStorage for RootDatabase {
|
||||||
impl ra_db::FilesDatabase {
|
impl ra_db::FilesDatabase {
|
||||||
|
|
|
@ -190,10 +190,7 @@ impl AnalysisImpl {
|
||||||
Some(it) => it,
|
Some(it) => it,
|
||||||
};
|
};
|
||||||
let root = descr.crate_root();
|
let root = descr.crate_root();
|
||||||
let file_id = root
|
let file_id = root.source().file_id();
|
||||||
.source()
|
|
||||||
.as_file()
|
|
||||||
.expect("root module always has a file as a source");
|
|
||||||
|
|
||||||
let crate_graph = self.db.crate_graph();
|
let crate_graph = self.db.crate_graph();
|
||||||
let crate_id = crate_graph.crate_id_for_crate_root(file_id);
|
let crate_id = crate_graph.crate_id_for_crate_root(file_id);
|
||||||
|
@ -213,7 +210,7 @@ impl AnalysisImpl {
|
||||||
let syntax = file.syntax();
|
let syntax = file.syntax();
|
||||||
if let Some(name_ref) = find_node_at_offset::<ast::NameRef>(syntax, position.offset) {
|
if let Some(name_ref) = find_node_at_offset::<ast::NameRef>(syntax, position.offset) {
|
||||||
if let Some(fn_descr) =
|
if let Some(fn_descr) =
|
||||||
hir::Function::guess_for_name_ref(&*self.db, position.file_id, name_ref)
|
hir::Function::guess_for_name_ref(&*self.db, position.file_id, name_ref)?
|
||||||
{
|
{
|
||||||
let scope = fn_descr.scope(&*self.db);
|
let scope = fn_descr.scope(&*self.db);
|
||||||
// First try to resolve the symbol locally
|
// First try to resolve the symbol locally
|
||||||
|
@ -260,11 +257,11 @@ impl AnalysisImpl {
|
||||||
Ok(vec![])
|
Ok(vec![])
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn find_all_refs(&self, position: FilePosition) -> Vec<(FileId, TextRange)> {
|
pub fn find_all_refs(&self, position: FilePosition) -> Cancelable<Vec<(FileId, TextRange)>> {
|
||||||
let file = self.db.source_file(position.file_id);
|
let file = self.db.source_file(position.file_id);
|
||||||
// Find the binding associated with the offset
|
// Find the binding associated with the offset
|
||||||
let (binding, descr) = match find_binding(&self.db, &file, position) {
|
let (binding, descr) = match find_binding(&self.db, &file, position)? {
|
||||||
None => return Vec::new(),
|
None => return Ok(Vec::new()),
|
||||||
Some(it) => it,
|
Some(it) => it,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -277,25 +274,36 @@ impl AnalysisImpl {
|
||||||
.map(|ref_desc| (position.file_id, ref_desc.range)),
|
.map(|ref_desc| (position.file_id, ref_desc.range)),
|
||||||
);
|
);
|
||||||
|
|
||||||
return ret;
|
return Ok(ret);
|
||||||
|
|
||||||
fn find_binding<'a>(
|
fn find_binding<'a>(
|
||||||
db: &db::RootDatabase,
|
db: &db::RootDatabase,
|
||||||
source_file: &'a SourceFileNode,
|
source_file: &'a SourceFileNode,
|
||||||
position: FilePosition,
|
position: FilePosition,
|
||||||
) -> Option<(ast::BindPat<'a>, hir::Function)> {
|
) -> Cancelable<Option<(ast::BindPat<'a>, hir::Function)>> {
|
||||||
let syntax = source_file.syntax();
|
let syntax = source_file.syntax();
|
||||||
if let Some(binding) = find_node_at_offset::<ast::BindPat>(syntax, position.offset) {
|
if let Some(binding) = find_node_at_offset::<ast::BindPat>(syntax, position.offset) {
|
||||||
let descr = hir::Function::guess_for_bind_pat(db, position.file_id, binding)?;
|
let descr = ctry!(hir::Function::guess_for_bind_pat(
|
||||||
return Some((binding, descr));
|
db,
|
||||||
|
position.file_id,
|
||||||
|
binding
|
||||||
|
)?);
|
||||||
|
return Ok(Some((binding, descr)));
|
||||||
};
|
};
|
||||||
let name_ref = find_node_at_offset::<ast::NameRef>(syntax, position.offset)?;
|
let name_ref = ctry!(find_node_at_offset::<ast::NameRef>(syntax, position.offset));
|
||||||
let descr = hir::Function::guess_for_name_ref(db, position.file_id, name_ref)?;
|
let descr = ctry!(hir::Function::guess_for_name_ref(
|
||||||
|
db,
|
||||||
|
position.file_id,
|
||||||
|
name_ref
|
||||||
|
)?);
|
||||||
let scope = descr.scope(db);
|
let scope = descr.scope(db);
|
||||||
let resolved = scope.resolve_local_name(name_ref)?;
|
let resolved = ctry!(scope.resolve_local_name(name_ref));
|
||||||
let resolved = resolved.ptr().resolve(source_file);
|
let resolved = resolved.ptr().resolve(source_file);
|
||||||
let binding = find_node_at_offset::<ast::BindPat>(syntax, resolved.range().end())?;
|
let binding = ctry!(find_node_at_offset::<ast::BindPat>(
|
||||||
Some((binding, descr))
|
syntax,
|
||||||
|
resolved.range().end()
|
||||||
|
));
|
||||||
|
Ok(Some((binding, descr)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -411,7 +419,9 @@ impl AnalysisImpl {
|
||||||
if fs.kind == FN_DEF {
|
if fs.kind == FN_DEF {
|
||||||
let fn_file = self.db.source_file(fn_file_id);
|
let fn_file = self.db.source_file(fn_file_id);
|
||||||
if let Some(fn_def) = find_node_at_offset(fn_file.syntax(), fs.node_range.start()) {
|
if let Some(fn_def) = find_node_at_offset(fn_file.syntax(), fs.node_range.start()) {
|
||||||
let descr = hir::Function::guess_from_source(&*self.db, fn_file_id, fn_def);
|
let descr = ctry!(hir::Function::guess_from_source(
|
||||||
|
&*self.db, fn_file_id, fn_def
|
||||||
|
)?);
|
||||||
if let Some(descriptor) = descr.signature_info(&*self.db) {
|
if let Some(descriptor) = descr.signature_info(&*self.db) {
|
||||||
// If we have a calling expression let's find which argument we are on
|
// If we have a calling expression let's find which argument we are on
|
||||||
let mut current_parameter = None;
|
let mut current_parameter = None;
|
||||||
|
|
|
@ -248,7 +248,7 @@ impl Analysis {
|
||||||
self.imp.approximately_resolve_symbol(position)
|
self.imp.approximately_resolve_symbol(position)
|
||||||
}
|
}
|
||||||
pub fn find_all_refs(&self, position: FilePosition) -> Cancelable<Vec<(FileId, TextRange)>> {
|
pub fn find_all_refs(&self, position: FilePosition) -> Cancelable<Vec<(FileId, TextRange)>> {
|
||||||
Ok(self.imp.find_all_refs(position))
|
self.imp.find_all_refs(position)
|
||||||
}
|
}
|
||||||
pub fn doc_comment_for(
|
pub fn doc_comment_for(
|
||||||
&self,
|
&self,
|
||||||
|
|
|
@ -7,10 +7,11 @@ use ra_syntax::{
|
||||||
use ra_db::{SourceRootId, LocationIntener, SyntaxDatabase, FileId, Cancelable};
|
use ra_db::{SourceRootId, LocationIntener, SyntaxDatabase, FileId, Cancelable};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
DefLoc, DefId, FnId,
|
DefLoc, DefId,
|
||||||
SourceFileItems, SourceItemId,
|
SourceFileItems, SourceItemId,
|
||||||
query_definitions,
|
query_definitions,
|
||||||
FnScopes,
|
FnScopes,
|
||||||
|
function::FnId,
|
||||||
module::{ModuleId, ModuleTree, ModuleSource,
|
module::{ModuleId, ModuleTree, ModuleSource,
|
||||||
nameres::{ItemMap, InputModuleItems}},
|
nameres::{ItemMap, InputModuleItems}},
|
||||||
};
|
};
|
||||||
|
@ -19,7 +20,6 @@ salsa::query_group! {
|
||||||
|
|
||||||
pub trait HirDatabase: SyntaxDatabase
|
pub trait HirDatabase: SyntaxDatabase
|
||||||
+ AsRef<LocationIntener<DefLoc, DefId>>
|
+ AsRef<LocationIntener<DefLoc, DefId>>
|
||||||
+ AsRef<LocationIntener<SourceItemId, FnId>>
|
|
||||||
{
|
{
|
||||||
fn fn_scopes(fn_id: FnId) -> Arc<FnScopes> {
|
fn fn_scopes(fn_id: FnId) -> Arc<FnScopes> {
|
||||||
type FnScopesQuery;
|
type FnScopesQuery;
|
||||||
|
|
|
@ -12,39 +12,49 @@ use ra_syntax::{
|
||||||
use ra_db::FileId;
|
use ra_db::FileId;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
FnId, HirDatabase, SourceItemId,
|
Cancelable,
|
||||||
|
DefLoc, DefKind, DefId, HirDatabase, SourceItemId,
|
||||||
|
Module,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub use self::scope::FnScopes;
|
pub use self::scope::FnScopes;
|
||||||
|
|
||||||
impl FnId {
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||||
pub fn get(db: &impl HirDatabase, file_id: FileId, fn_def: ast::FnDef) -> FnId {
|
pub struct FnId(pub(crate) DefId);
|
||||||
let file_items = db.file_items(file_id);
|
|
||||||
let item_id = file_items.id_of(fn_def.syntax());
|
|
||||||
let item_id = SourceItemId { file_id, item_id };
|
|
||||||
FnId::from_loc(db, &item_id)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Function {
|
pub struct Function {
|
||||||
fn_id: FnId,
|
fn_id: FnId,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Function {
|
impl Function {
|
||||||
|
pub(crate) fn new(def_id: DefId) -> Function {
|
||||||
|
let fn_id = FnId(def_id);
|
||||||
|
Function { fn_id }
|
||||||
|
}
|
||||||
|
|
||||||
pub fn guess_from_source(
|
pub fn guess_from_source(
|
||||||
db: &impl HirDatabase,
|
db: &impl HirDatabase,
|
||||||
file_id: FileId,
|
file_id: FileId,
|
||||||
fn_def: ast::FnDef,
|
fn_def: ast::FnDef,
|
||||||
) -> Function {
|
) -> Cancelable<Option<Function>> {
|
||||||
let fn_id = FnId::get(db, file_id, fn_def);
|
let module = ctry!(Module::guess_from_child_node(db, file_id, fn_def.syntax())?);
|
||||||
Function { fn_id }
|
let file_items = db.file_items(file_id);
|
||||||
|
let item_id = file_items.id_of(fn_def.syntax());
|
||||||
|
let source_item_id = SourceItemId { file_id, item_id };
|
||||||
|
let def_loc = DefLoc {
|
||||||
|
kind: DefKind::Function,
|
||||||
|
source_root_id: module.source_root_id,
|
||||||
|
module_id: module.module_id,
|
||||||
|
source_item_id,
|
||||||
|
};
|
||||||
|
Ok(Some(Function::new(def_loc.id(db))))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn guess_for_name_ref(
|
pub fn guess_for_name_ref(
|
||||||
db: &impl HirDatabase,
|
db: &impl HirDatabase,
|
||||||
file_id: FileId,
|
file_id: FileId,
|
||||||
name_ref: ast::NameRef,
|
name_ref: ast::NameRef,
|
||||||
) -> Option<Function> {
|
) -> Cancelable<Option<Function>> {
|
||||||
Function::guess_for_node(db, file_id, name_ref.syntax())
|
Function::guess_for_node(db, file_id, name_ref.syntax())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -52,7 +62,7 @@ impl Function {
|
||||||
db: &impl HirDatabase,
|
db: &impl HirDatabase,
|
||||||
file_id: FileId,
|
file_id: FileId,
|
||||||
bind_pat: ast::BindPat,
|
bind_pat: ast::BindPat,
|
||||||
) -> Option<Function> {
|
) -> Cancelable<Option<Function>> {
|
||||||
Function::guess_for_node(db, file_id, bind_pat.syntax())
|
Function::guess_for_node(db, file_id, bind_pat.syntax())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,10 +70,9 @@ impl Function {
|
||||||
db: &impl HirDatabase,
|
db: &impl HirDatabase,
|
||||||
file_id: FileId,
|
file_id: FileId,
|
||||||
node: SyntaxNodeRef,
|
node: SyntaxNodeRef,
|
||||||
) -> Option<Function> {
|
) -> Cancelable<Option<Function>> {
|
||||||
let fn_def = node.ancestors().find_map(ast::FnDef::cast)?;
|
let fn_def = ctry!(node.ancestors().find_map(ast::FnDef::cast));
|
||||||
let res = Function::guess_from_source(db, file_id, fn_def);
|
Function::guess_from_source(db, file_id, fn_def)
|
||||||
Some(res)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn scope(&self, db: &impl HirDatabase) -> Arc<FnScopes> {
|
pub fn scope(&self, db: &impl HirDatabase) -> Arc<FnScopes> {
|
||||||
|
|
|
@ -41,63 +41,58 @@ pub use self::{
|
||||||
|
|
||||||
pub use self::function::FnSignatureInfo;
|
pub use self::function::FnSignatureInfo;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
/// Def's are a core concept of hir. A `Def` is an Item (function, module, etc)
|
||||||
pub struct FnId(u32);
|
/// in a specific module.
|
||||||
ra_db::impl_numeric_id!(FnId);
|
|
||||||
|
|
||||||
impl FnId {
|
|
||||||
pub fn from_loc(
|
|
||||||
db: &impl AsRef<LocationIntener<SourceItemId, FnId>>,
|
|
||||||
loc: &SourceItemId,
|
|
||||||
) -> FnId {
|
|
||||||
db.as_ref().loc2id(loc)
|
|
||||||
}
|
|
||||||
pub fn loc(self, db: &impl AsRef<LocationIntener<SourceItemId, FnId>>) -> SourceItemId {
|
|
||||||
db.as_ref().id2loc(self)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||||
pub struct DefId(u32);
|
pub struct DefId(u32);
|
||||||
ra_db::impl_numeric_id!(DefId);
|
ra_db::impl_numeric_id!(DefId);
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||||
|
pub(crate) enum DefKind {
|
||||||
|
Module,
|
||||||
|
Function,
|
||||||
|
Item,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
pub enum DefLoc {
|
pub struct DefLoc {
|
||||||
Module {
|
pub(crate) kind: DefKind,
|
||||||
id: ModuleId,
|
source_root_id: SourceRootId,
|
||||||
source_root: SourceRootId,
|
module_id: ModuleId,
|
||||||
},
|
source_item_id: SourceItemId,
|
||||||
Item {
|
|
||||||
source_item_id: SourceItemId,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DefId {
|
impl DefId {
|
||||||
pub fn loc(self, db: &impl AsRef<LocationIntener<DefLoc, DefId>>) -> DefLoc {
|
pub(crate) fn loc(self, db: &impl AsRef<LocationIntener<DefLoc, DefId>>) -> DefLoc {
|
||||||
db.as_ref().id2loc(self)
|
db.as_ref().id2loc(self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DefLoc {
|
impl DefLoc {
|
||||||
pub fn id(&self, db: &impl AsRef<LocationIntener<DefLoc, DefId>>) -> DefId {
|
pub(crate) fn id(&self, db: &impl AsRef<LocationIntener<DefLoc, DefId>>) -> DefId {
|
||||||
db.as_ref().loc2id(&self)
|
db.as_ref().loc2id(&self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum Def {
|
pub enum Def {
|
||||||
Module(Module),
|
Module(Module),
|
||||||
|
Function(Function),
|
||||||
Item,
|
Item,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DefId {
|
impl DefId {
|
||||||
pub fn resolve(self, db: &impl HirDatabase) -> Cancelable<Def> {
|
pub fn resolve(self, db: &impl HirDatabase) -> Cancelable<Def> {
|
||||||
let loc = self.loc(db);
|
let loc = self.loc(db);
|
||||||
let res = match loc {
|
let res = match loc.kind {
|
||||||
DefLoc::Module { id, source_root } => {
|
DefKind::Module => {
|
||||||
let descr = Module::new(db, source_root, id)?;
|
let module = Module::new(db, loc.source_root_id, loc.module_id)?;
|
||||||
Def::Module(descr)
|
Def::Module(module)
|
||||||
}
|
}
|
||||||
DefLoc::Item { .. } => Def::Item,
|
DefKind::Function => {
|
||||||
|
let function = Function::new(self);
|
||||||
|
Def::Function(function)
|
||||||
|
}
|
||||||
|
DefKind::Item => Def::Item,
|
||||||
};
|
};
|
||||||
Ok(res)
|
Ok(res)
|
||||||
}
|
}
|
||||||
|
@ -131,6 +126,10 @@ impl SourceFileItems {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
id
|
id
|
||||||
}
|
}
|
||||||
|
pub fn id_of_source_file(&self) -> SourceFileItemId {
|
||||||
|
let (id, _syntax) = self.arena.iter().next().unwrap();
|
||||||
|
id
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Index<SourceFileItemId> for SourceFileItems {
|
impl Index<SourceFileItemId> for SourceFileItems {
|
||||||
|
|
|
@ -6,7 +6,7 @@ use ra_db::{LocationIntener, BaseDatabase, FilePosition, mock::FileMap, FileId,
|
||||||
use relative_path::RelativePathBuf;
|
use relative_path::RelativePathBuf;
|
||||||
use test_utils::{parse_fixture, CURSOR_MARKER, extract_offset};
|
use test_utils::{parse_fixture, CURSOR_MARKER, extract_offset};
|
||||||
|
|
||||||
use crate::{db, DefId, DefLoc, FnId, SourceItemId};
|
use crate::{db, DefId, DefLoc};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub(crate) struct MockDatabase {
|
pub(crate) struct MockDatabase {
|
||||||
|
@ -65,7 +65,6 @@ impl MockDatabase {
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
struct IdMaps {
|
struct IdMaps {
|
||||||
fns: LocationIntener<SourceItemId, FnId>,
|
|
||||||
defs: LocationIntener<DefLoc, DefId>,
|
defs: LocationIntener<DefLoc, DefId>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -117,12 +116,6 @@ impl AsRef<LocationIntener<DefLoc, DefId>> for MockDatabase {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AsRef<LocationIntener<SourceItemId, FnId>> for MockDatabase {
|
|
||||||
fn as_ref(&self) -> &LocationIntener<SourceItemId, FnId> {
|
|
||||||
&self.id_maps.fns
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl MockDatabase {
|
impl MockDatabase {
|
||||||
pub(crate) fn log(&self, f: impl FnOnce()) -> Vec<salsa::Event<MockDatabase>> {
|
pub(crate) fn log(&self, f: impl FnOnce()) -> Vec<salsa::Event<MockDatabase>> {
|
||||||
*self.events.lock() = Some(Vec::new());
|
*self.events.lock() = Some(Vec::new());
|
||||||
|
|
|
@ -66,7 +66,7 @@ fn create_module_tree<'a>(
|
||||||
|
|
||||||
let source_root = db.source_root(source_root);
|
let source_root = db.source_root(source_root);
|
||||||
for &file_id in source_root.files.iter() {
|
for &file_id in source_root.files.iter() {
|
||||||
let source = ModuleSource::SourceFile(file_id);
|
let source = ModuleSource::new_file(db, file_id);
|
||||||
if visited.contains(&source) {
|
if visited.contains(&source) {
|
||||||
continue; // TODO: use explicit crate_roots here
|
continue; // TODO: use explicit crate_roots here
|
||||||
}
|
}
|
||||||
|
@ -126,7 +126,7 @@ fn build_subtree(
|
||||||
visited,
|
visited,
|
||||||
roots,
|
roots,
|
||||||
Some(link),
|
Some(link),
|
||||||
ModuleSource::SourceFile(file_id),
|
ModuleSource::new_file(db, file_id),
|
||||||
),
|
),
|
||||||
})
|
})
|
||||||
.collect::<Cancelable<Vec<_>>>()?;
|
.collect::<Cancelable<Vec<_>>>()?;
|
||||||
|
@ -157,13 +157,8 @@ fn resolve_submodule(
|
||||||
name: &SmolStr,
|
name: &SmolStr,
|
||||||
file_resolver: &FileResolverImp,
|
file_resolver: &FileResolverImp,
|
||||||
) -> (Vec<FileId>, Option<Problem>) {
|
) -> (Vec<FileId>, Option<Problem>) {
|
||||||
let file_id = match source {
|
// TODO: handle submodules of inline modules properly
|
||||||
ModuleSource::SourceFile(it) => it,
|
let file_id = source.file_id();
|
||||||
ModuleSource::Module(..) => {
|
|
||||||
// TODO
|
|
||||||
return (Vec::new(), None);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let mod_name = file_resolver.file_stem(file_id);
|
let mod_name = file_resolver.file_stem(file_id);
|
||||||
let is_dir_owner = mod_name == "mod" || mod_name == "lib" || mod_name == "main";
|
let is_dir_owner = mod_name == "mod" || mod_name == "lib" || mod_name == "main";
|
||||||
|
|
||||||
|
|
|
@ -8,13 +8,13 @@ use ra_editor::find_node_at_offset;
|
||||||
use ra_syntax::{
|
use ra_syntax::{
|
||||||
algo::generate,
|
algo::generate,
|
||||||
ast::{self, AstNode, NameOwner},
|
ast::{self, AstNode, NameOwner},
|
||||||
SmolStr, SyntaxNode,
|
SmolStr, SyntaxNode, SyntaxNodeRef,
|
||||||
};
|
};
|
||||||
use ra_db::{SourceRootId, FileId, FilePosition, Cancelable};
|
use ra_db::{SourceRootId, FileId, FilePosition, Cancelable};
|
||||||
use relative_path::RelativePathBuf;
|
use relative_path::RelativePathBuf;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
DefLoc, DefId, Path, PathKind, HirDatabase, SourceItemId,
|
DefKind, DefLoc, DefId, Path, PathKind, HirDatabase, SourceItemId, SourceFileItemId,
|
||||||
arena::{Arena, Id},
|
arena::{Arena, Id},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -25,8 +25,8 @@ pub use self::nameres::ModuleScope;
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Module {
|
pub struct Module {
|
||||||
tree: Arc<ModuleTree>,
|
tree: Arc<ModuleTree>,
|
||||||
source_root_id: SourceRootId,
|
pub(crate) source_root_id: SourceRootId,
|
||||||
module_id: ModuleId,
|
pub(crate) module_id: ModuleId,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Module {
|
impl Module {
|
||||||
|
@ -37,7 +37,8 @@ impl Module {
|
||||||
db: &impl HirDatabase,
|
db: &impl HirDatabase,
|
||||||
file_id: FileId,
|
file_id: FileId,
|
||||||
) -> Cancelable<Option<Module>> {
|
) -> Cancelable<Option<Module>> {
|
||||||
Module::guess_from_source(db, file_id, ModuleSource::SourceFile(file_id))
|
let module_source = ModuleSource::new_file(db, file_id);
|
||||||
|
Module::guess_from_source(db, module_source)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Lookup `Module` by position in the source code. Note that this
|
/// Lookup `Module` by position in the source code. Note that this
|
||||||
|
@ -51,17 +52,33 @@ impl Module {
|
||||||
let module_source = match find_node_at_offset::<ast::Module>(file.syntax(), position.offset)
|
let module_source = match find_node_at_offset::<ast::Module>(file.syntax(), position.offset)
|
||||||
{
|
{
|
||||||
Some(m) if !m.has_semi() => ModuleSource::new_inline(db, position.file_id, m),
|
Some(m) if !m.has_semi() => ModuleSource::new_inline(db, position.file_id, m),
|
||||||
_ => ModuleSource::SourceFile(position.file_id),
|
_ => ModuleSource::new_file(db, position.file_id),
|
||||||
};
|
};
|
||||||
Module::guess_from_source(db, position.file_id, module_source)
|
Module::guess_from_source(db, module_source)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn guess_from_child_node(
|
||||||
|
db: &impl HirDatabase,
|
||||||
|
file_id: FileId,
|
||||||
|
node: SyntaxNodeRef,
|
||||||
|
) -> Cancelable<Option<Module>> {
|
||||||
|
let module_source = if let Some(m) = node
|
||||||
|
.ancestors()
|
||||||
|
.filter_map(ast::Module::cast)
|
||||||
|
.find(|it| !it.has_semi())
|
||||||
|
{
|
||||||
|
ModuleSource::new_inline(db, file_id, m)
|
||||||
|
} else {
|
||||||
|
ModuleSource::new_file(db, file_id)
|
||||||
|
};
|
||||||
|
Module::guess_from_source(db, module_source)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn guess_from_source(
|
fn guess_from_source(
|
||||||
db: &impl HirDatabase,
|
db: &impl HirDatabase,
|
||||||
file_id: FileId,
|
|
||||||
module_source: ModuleSource,
|
module_source: ModuleSource,
|
||||||
) -> Cancelable<Option<Module>> {
|
) -> Cancelable<Option<Module>> {
|
||||||
let source_root_id = db.file_source_root(file_id);
|
let source_root_id = db.file_source_root(module_source.file_id());
|
||||||
let module_tree = db.module_tree(source_root_id)?;
|
let module_tree = db.module_tree(source_root_id)?;
|
||||||
|
|
||||||
let res = match module_tree.any_module_for_source(module_source) {
|
let res = match module_tree.any_module_for_source(module_source) {
|
||||||
|
@ -127,9 +144,11 @@ impl Module {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn def_id(&self, db: &impl HirDatabase) -> DefId {
|
pub fn def_id(&self, db: &impl HirDatabase) -> DefId {
|
||||||
let def_loc = DefLoc::Module {
|
let def_loc = DefLoc {
|
||||||
id: self.module_id,
|
kind: DefKind::Module,
|
||||||
source_root: self.source_root_id,
|
source_root_id: self.source_root_id,
|
||||||
|
module_id: self.module_id,
|
||||||
|
source_item_id: self.module_id.source(&self.tree).0,
|
||||||
};
|
};
|
||||||
def_loc.id(db)
|
def_loc.id(db)
|
||||||
}
|
}
|
||||||
|
@ -161,7 +180,12 @@ impl Module {
|
||||||
let segments = path.segments;
|
let segments = path.segments;
|
||||||
for name in segments.iter() {
|
for name in segments.iter() {
|
||||||
let module = match curr.loc(db) {
|
let module = match curr.loc(db) {
|
||||||
DefLoc::Module { id, source_root } => Module::new(db, source_root, id)?,
|
DefLoc {
|
||||||
|
kind: DefKind::Module,
|
||||||
|
source_root_id,
|
||||||
|
module_id,
|
||||||
|
..
|
||||||
|
} => Module::new(db, source_root_id, module_id)?,
|
||||||
_ => return Ok(None),
|
_ => return Ok(None),
|
||||||
};
|
};
|
||||||
let scope = module.scope(db)?;
|
let scope = module.scope(db)?;
|
||||||
|
@ -209,10 +233,7 @@ impl ModuleTree {
|
||||||
/// `ModuleSource` is the syntax tree element that produced this module:
|
/// `ModuleSource` is the syntax tree element that produced this module:
|
||||||
/// either a file, or an inlinde module.
|
/// either a file, or an inlinde module.
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||||
pub enum ModuleSource {
|
pub struct ModuleSource(SourceItemId);
|
||||||
SourceFile(FileId),
|
|
||||||
Module(SourceItemId),
|
|
||||||
}
|
|
||||||
|
|
||||||
/// An owned syntax node for a module. Unlike `ModuleSource`,
|
/// An owned syntax node for a module. Unlike `ModuleSource`,
|
||||||
/// this holds onto the AST for the whole file.
|
/// this holds onto the AST for the whole file.
|
||||||
|
@ -310,45 +331,41 @@ pub struct ModuleData {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ModuleSource {
|
impl ModuleSource {
|
||||||
|
// precondition: item_id **must** point to module
|
||||||
|
fn new(file_id: FileId, item_id: SourceFileItemId) -> ModuleSource {
|
||||||
|
let source_item_id = SourceItemId { file_id, item_id };
|
||||||
|
ModuleSource(source_item_id)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn new_file(db: &impl HirDatabase, file_id: FileId) -> ModuleSource {
|
||||||
|
let file_items = db.file_items(file_id);
|
||||||
|
let item_id = file_items.id_of_source_file();
|
||||||
|
ModuleSource::new(file_id, item_id)
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn new_inline(
|
pub(crate) fn new_inline(
|
||||||
db: &impl HirDatabase,
|
db: &impl HirDatabase,
|
||||||
file_id: FileId,
|
file_id: FileId,
|
||||||
module: ast::Module,
|
m: ast::Module,
|
||||||
) -> ModuleSource {
|
) -> ModuleSource {
|
||||||
assert!(!module.has_semi());
|
assert!(!m.has_semi());
|
||||||
let items = db.file_items(file_id);
|
let file_items = db.file_items(file_id);
|
||||||
let item_id = items.id_of(module.syntax());
|
let item_id = file_items.id_of(m.syntax());
|
||||||
let id = SourceItemId { file_id, item_id };
|
ModuleSource::new(file_id, item_id)
|
||||||
ModuleSource::Module(id)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn as_file(self) -> Option<FileId> {
|
|
||||||
match self {
|
|
||||||
ModuleSource::SourceFile(f) => Some(f),
|
|
||||||
ModuleSource::Module(..) => None,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn file_id(self) -> FileId {
|
pub fn file_id(self) -> FileId {
|
||||||
match self {
|
self.0.file_id
|
||||||
ModuleSource::SourceFile(f) => f,
|
|
||||||
ModuleSource::Module(source_item_id) => source_item_id.file_id,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn resolve(self, db: &impl HirDatabase) -> ModuleSourceNode {
|
pub(crate) fn resolve(self, db: &impl HirDatabase) -> ModuleSourceNode {
|
||||||
match self {
|
let syntax_node = db.file_item(self.0);
|
||||||
ModuleSource::SourceFile(file_id) => {
|
let syntax_node = syntax_node.borrowed();
|
||||||
let syntax = db.source_file(file_id);
|
if let Some(file) = ast::SourceFile::cast(syntax_node) {
|
||||||
ModuleSourceNode::SourceFile(syntax.ast().owned())
|
return ModuleSourceNode::SourceFile(file.owned());
|
||||||
}
|
|
||||||
ModuleSource::Module(item_id) => {
|
|
||||||
let syntax = db.file_item(item_id);
|
|
||||||
let syntax = syntax.borrowed();
|
|
||||||
let module = ast::Module::cast(syntax).unwrap();
|
|
||||||
ModuleSourceNode::Module(module.owned())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
let module = ast::Module::cast(syntax_node).unwrap();
|
||||||
|
ModuleSourceNode::Module(module.owned())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -28,7 +28,7 @@ use ra_db::SourceRootId;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
Cancelable, FileId,
|
Cancelable, FileId,
|
||||||
DefId, DefLoc,
|
DefId, DefLoc, DefKind,
|
||||||
SourceItemId, SourceFileItemId, SourceFileItems,
|
SourceItemId, SourceFileItemId, SourceFileItems,
|
||||||
Path, PathKind,
|
Path, PathKind,
|
||||||
HirDatabase,
|
HirDatabase,
|
||||||
|
@ -247,7 +247,10 @@ where
|
||||||
// handle submodules separatelly
|
// handle submodules separatelly
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let def_loc = DefLoc::Item {
|
let def_loc = DefLoc {
|
||||||
|
kind: DefKind::Item,
|
||||||
|
source_root_id: self.source_root,
|
||||||
|
module_id,
|
||||||
source_item_id: SourceItemId {
|
source_item_id: SourceItemId {
|
||||||
file_id,
|
file_id,
|
||||||
item_id: item.id,
|
item_id: item.id,
|
||||||
|
@ -261,10 +264,12 @@ where
|
||||||
module_items.items.insert(item.name.clone(), resolution);
|
module_items.items.insert(item.name.clone(), resolution);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (name, mod_id) in module_id.children(&self.module_tree) {
|
for (name, module_id) in module_id.children(&self.module_tree) {
|
||||||
let def_loc = DefLoc::Module {
|
let def_loc = DefLoc {
|
||||||
id: mod_id,
|
kind: DefKind::Module,
|
||||||
source_root: self.source_root,
|
source_root_id: self.source_root,
|
||||||
|
module_id,
|
||||||
|
source_item_id: module_id.source(&self.module_tree).0,
|
||||||
};
|
};
|
||||||
let def_id = def_loc.id(self.db);
|
let def_id = def_loc.id(self.db);
|
||||||
let resolution = Resolution {
|
let resolution = Resolution {
|
||||||
|
@ -316,7 +321,11 @@ where
|
||||||
|
|
||||||
if !is_last {
|
if !is_last {
|
||||||
curr = match def_id.loc(self.db) {
|
curr = match def_id.loc(self.db) {
|
||||||
DefLoc::Module { id, .. } => id,
|
DefLoc {
|
||||||
|
kind: DefKind::Module,
|
||||||
|
module_id,
|
||||||
|
..
|
||||||
|
} => module_id,
|
||||||
_ => return,
|
_ => return,
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -11,21 +11,21 @@ use ra_syntax::{
|
||||||
use ra_db::{SourceRootId, FileId, Cancelable,};
|
use ra_db::{SourceRootId, FileId, Cancelable,};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
FnId,
|
SourceFileItems, SourceItemId, DefKind,
|
||||||
SourceFileItems, SourceItemId,
|
db::HirDatabase,
|
||||||
db::HirDatabase,
|
function::{FnScopes, FnId},
|
||||||
function::FnScopes,
|
module::{
|
||||||
module::{
|
ModuleSource, ModuleSourceNode, ModuleId,
|
||||||
ModuleSource, ModuleSourceNode, ModuleId,
|
imp::Submodule,
|
||||||
imp::Submodule,
|
nameres::{InputModuleItems, ItemMap, Resolver},
|
||||||
nameres::{InputModuleItems, ItemMap, Resolver},
|
},
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Resolve `FnId` to the corresponding `SyntaxNode`
|
/// Resolve `FnId` to the corresponding `SyntaxNode`
|
||||||
pub(super) fn fn_syntax(db: &impl HirDatabase, fn_id: FnId) -> FnDefNode {
|
pub(super) fn fn_syntax(db: &impl HirDatabase, fn_id: FnId) -> FnDefNode {
|
||||||
let item_id = fn_id.loc(db);
|
let def_loc = fn_id.0.loc(db);
|
||||||
let syntax = db.file_item(item_id);
|
assert!(def_loc.kind == DefKind::Function);
|
||||||
|
let syntax = db.file_item(def_loc.source_item_id);
|
||||||
FnDef::cast(syntax.borrowed()).unwrap().owned()
|
FnDef::cast(syntax.borrowed()).unwrap().owned()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,9 +36,10 @@ pub(super) fn fn_scopes(db: &impl HirDatabase, fn_id: FnId) -> Arc<FnScopes> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn file_items(db: &impl HirDatabase, file_id: FileId) -> Arc<SourceFileItems> {
|
pub(super) fn file_items(db: &impl HirDatabase, file_id: FileId) -> Arc<SourceFileItems> {
|
||||||
let source_file = db.source_file(file_id);
|
|
||||||
let source_file = source_file.borrowed();
|
|
||||||
let mut res = SourceFileItems::default();
|
let mut res = SourceFileItems::default();
|
||||||
|
let source_file = db.source_file(file_id);
|
||||||
|
res.alloc(source_file.syntax().owned());
|
||||||
|
let source_file = source_file.borrowed();
|
||||||
source_file
|
source_file
|
||||||
.syntax()
|
.syntax()
|
||||||
.descendants()
|
.descendants()
|
||||||
|
|
Loading…
Reference in a new issue