Merge #245
245: File items r=matklad a=matklad Co-authored-by: Aleksey Kladov <aleksey.kladov@gmail.com>
This commit is contained in:
commit
0bc6f5802f
7 changed files with 175 additions and 87 deletions
|
@ -46,9 +46,12 @@ pub(super) fn completions(
|
|||
.iter()
|
||||
.filter(|(_name, res)| {
|
||||
// Don't expose this item
|
||||
match res.import_name {
|
||||
match res.import {
|
||||
None => true,
|
||||
Some(ptr) => !ptr.range().is_subrange(&name_ref.syntax().range()),
|
||||
Some(import) => {
|
||||
let range = import.range(db, module.source().file_id());
|
||||
!range.is_subrange(&name_ref.syntax().range())
|
||||
}
|
||||
}
|
||||
})
|
||||
.map(|(name, _res)| CompletionItem {
|
||||
|
|
|
@ -7,10 +7,7 @@ use salsa::{self, Database};
|
|||
|
||||
use crate::{
|
||||
db,
|
||||
descriptors::{
|
||||
DescriptorDatabase, FnScopesQuery, FnSyntaxQuery, ModuleTreeQuery,
|
||||
SubmodulesQuery, ItemMapQuery, InputModuleItemsQuery,
|
||||
},
|
||||
descriptors,
|
||||
symbol_index::SymbolIndex,
|
||||
syntax_ptr::SyntaxPtr,
|
||||
loc2id::{IdMaps, IdDatabase},
|
||||
|
@ -125,13 +122,15 @@ salsa::database_storage! {
|
|||
fn file_symbols() for FileSymbolsQuery;
|
||||
fn resolve_syntax_ptr() for ResolveSyntaxPtrQuery;
|
||||
}
|
||||
impl DescriptorDatabase {
|
||||
fn module_tree() for ModuleTreeQuery;
|
||||
fn fn_scopes() for FnScopesQuery;
|
||||
fn _input_module_items() for InputModuleItemsQuery;
|
||||
fn _item_map() for ItemMapQuery;
|
||||
fn _fn_syntax() for FnSyntaxQuery;
|
||||
fn _submodules() for SubmodulesQuery;
|
||||
impl descriptors::DescriptorDatabase {
|
||||
fn module_tree() for descriptors::ModuleTreeQuery;
|
||||
fn fn_scopes() for descriptors::FnScopesQuery;
|
||||
fn _file_items() for descriptors::FileItemsQuery;
|
||||
fn _file_item() for descriptors::FileItemQuery;
|
||||
fn _input_module_items() for descriptors::InputModuleItemsQuery;
|
||||
fn _item_map() for descriptors::ItemMapQuery;
|
||||
fn _fn_syntax() for descriptors::FnSyntaxQuery;
|
||||
fn _submodules() for descriptors::SubmodulesQuery;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,13 +6,14 @@ use std::sync::Arc;
|
|||
|
||||
use ra_syntax::{
|
||||
ast::{self, FnDefNode, AstNode},
|
||||
TextRange,
|
||||
TextRange, SyntaxNode,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
FileId,
|
||||
db::SyntaxDatabase,
|
||||
descriptors::function::{resolve_local_name, FnId, FnScopes},
|
||||
descriptors::module::{ModuleId, ModuleTree, ModuleSource, nameres::{ItemMap, InputModuleItems}},
|
||||
descriptors::module::{ModuleId, ModuleTree, ModuleSource, nameres::{ItemMap, InputModuleItems, FileItems}},
|
||||
input::SourceRootId,
|
||||
loc2id::IdDatabase,
|
||||
syntax_ptr::LocalSyntaxPtr,
|
||||
|
@ -20,6 +21,7 @@ use crate::{
|
|||
};
|
||||
|
||||
pub(crate) use self::path::{Path, PathKind};
|
||||
pub(crate) use self::module::nameres::FileItemId;
|
||||
|
||||
salsa::query_group! {
|
||||
pub(crate) trait DescriptorDatabase: SyntaxDatabase + IdDatabase {
|
||||
|
@ -28,6 +30,18 @@ salsa::query_group! {
|
|||
use fn function::imp::fn_scopes;
|
||||
}
|
||||
|
||||
fn _file_items(file_id: FileId) -> Arc<FileItems> {
|
||||
type FileItemsQuery;
|
||||
storage volatile;
|
||||
use fn module::nameres::file_items;
|
||||
}
|
||||
|
||||
fn _file_item(file_id: FileId, file_item_id: FileItemId) -> SyntaxNode {
|
||||
type FileItemQuery;
|
||||
storage volatile;
|
||||
use fn module::nameres::file_item;
|
||||
}
|
||||
|
||||
fn _input_module_items(source_root_id: SourceRootId, module_id: ModuleId) -> Cancelable<Arc<InputModuleItems>> {
|
||||
type InputModuleItemsQuery;
|
||||
use fn module::nameres::input_module_items;
|
||||
|
|
|
@ -17,27 +17,83 @@
|
|||
use std::{
|
||||
sync::Arc,
|
||||
time::Instant,
|
||||
ops::Index,
|
||||
};
|
||||
|
||||
use rustc_hash::FxHashMap;
|
||||
|
||||
use ra_syntax::{
|
||||
SyntaxNode, SyntaxNodeRef, TextRange,
|
||||
SmolStr, SyntaxKind::{self, *},
|
||||
ast::{self, ModuleItemOwner}
|
||||
ast::{self, ModuleItemOwner, AstNode}
|
||||
};
|
||||
|
||||
use crate::{
|
||||
Cancelable,
|
||||
Cancelable, FileId,
|
||||
loc2id::{DefId, DefLoc},
|
||||
descriptors::{
|
||||
Path, PathKind,
|
||||
DescriptorDatabase,
|
||||
module::{ModuleId, ModuleTree, ModuleSourceNode},
|
||||
},
|
||||
syntax_ptr::{LocalSyntaxPtr},
|
||||
input::SourceRootId,
|
||||
arena::{Arena, Id}
|
||||
};
|
||||
|
||||
/// Identifier of item within a specific file. This is stable over reparses, so
|
||||
/// it's OK to use it as a salsa key/value.
|
||||
pub(crate) type FileItemId = Id<SyntaxNode>;
|
||||
|
||||
/// Maps item's `SyntaxNode`s to `FileItemId` and back.
|
||||
#[derive(Debug, PartialEq, Eq, Default)]
|
||||
pub(crate) struct FileItems {
|
||||
arena: Arena<SyntaxNode>,
|
||||
}
|
||||
|
||||
impl FileItems {
|
||||
fn alloc(&mut self, item: SyntaxNode) -> FileItemId {
|
||||
self.arena.alloc(item)
|
||||
}
|
||||
fn id_of(&self, item: SyntaxNodeRef) -> FileItemId {
|
||||
let (id, _item) = self
|
||||
.arena
|
||||
.iter()
|
||||
.find(|(_id, i)| i.borrowed() == item)
|
||||
.unwrap();
|
||||
id
|
||||
}
|
||||
}
|
||||
|
||||
impl Index<FileItemId> for FileItems {
|
||||
type Output = SyntaxNode;
|
||||
fn index(&self, idx: FileItemId) -> &SyntaxNode {
|
||||
&self.arena[idx]
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn file_items(db: &impl DescriptorDatabase, file_id: FileId) -> Arc<FileItems> {
|
||||
let source_file = db.file_syntax(file_id);
|
||||
let source_file = source_file.borrowed();
|
||||
let mut res = FileItems::default();
|
||||
source_file
|
||||
.syntax()
|
||||
.descendants()
|
||||
.filter_map(ast::ModuleItem::cast)
|
||||
.map(|it| it.syntax().owned())
|
||||
.for_each(|it| {
|
||||
res.alloc(it);
|
||||
});
|
||||
Arc::new(res)
|
||||
}
|
||||
|
||||
pub(crate) fn file_item(
|
||||
db: &impl DescriptorDatabase,
|
||||
file_id: FileId,
|
||||
file_item_id: FileItemId,
|
||||
) -> SyntaxNode {
|
||||
db._file_items(file_id)[file_item_id].clone()
|
||||
}
|
||||
|
||||
/// Item map is the result of the name resolution. Item map contains, for each
|
||||
/// module, the set of visible items.
|
||||
#[derive(Default, Debug, PartialEq, Eq)]
|
||||
|
@ -62,17 +118,44 @@ pub(crate) struct InputModuleItems {
|
|||
imports: Vec<Import>,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
struct ModuleItem {
|
||||
id: FileItemId,
|
||||
name: SmolStr,
|
||||
kind: SyntaxKind,
|
||||
vis: Vis,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
enum Vis {
|
||||
// Priv,
|
||||
Other,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
struct Import {
|
||||
path: Path,
|
||||
kind: ImportKind,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub(crate) struct NamedImport {
|
||||
file_item_id: FileItemId,
|
||||
relative_range: TextRange,
|
||||
}
|
||||
|
||||
impl NamedImport {
|
||||
pub(crate) fn range(&self, db: &impl DescriptorDatabase, file_id: FileId) -> TextRange {
|
||||
let syntax = db._file_item(file_id, self.file_item_id);
|
||||
let offset = syntax.borrowed().range().start();
|
||||
self.relative_range + offset
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
enum ImportKind {
|
||||
Glob,
|
||||
// TODO: make offset independent
|
||||
Named(LocalSyntaxPtr),
|
||||
Named(NamedImport),
|
||||
}
|
||||
|
||||
pub(crate) fn input_module_items(
|
||||
|
@ -82,10 +165,11 @@ pub(crate) fn input_module_items(
|
|||
) -> Cancelable<Arc<InputModuleItems>> {
|
||||
let module_tree = db._module_tree(source_root)?;
|
||||
let source = module_id.source(&module_tree);
|
||||
let file_items = db._file_items(source.file_id());
|
||||
let res = match source.resolve(db) {
|
||||
ModuleSourceNode::SourceFile(it) => {
|
||||
let items = it.borrowed().items();
|
||||
InputModuleItems::new(items)
|
||||
InputModuleItems::new(&file_items, items)
|
||||
}
|
||||
ModuleSourceNode::Module(it) => {
|
||||
let items = it
|
||||
|
@ -93,7 +177,7 @@ pub(crate) fn input_module_items(
|
|||
.item_list()
|
||||
.into_iter()
|
||||
.flat_map(|it| it.items());
|
||||
InputModuleItems::new(items)
|
||||
InputModuleItems::new(&file_items, items)
|
||||
}
|
||||
};
|
||||
Ok(Arc::new(res))
|
||||
|
@ -112,7 +196,6 @@ pub(crate) fn item_map(
|
|||
Ok((id, items))
|
||||
})
|
||||
.collect::<Cancelable<FxHashMap<_, _>>>()?;
|
||||
|
||||
let mut resolver = Resolver {
|
||||
db: db,
|
||||
input: &input,
|
||||
|
@ -134,8 +217,7 @@ pub(crate) struct Resolution {
|
|||
/// None for unresolved
|
||||
pub(crate) def_id: Option<DefId>,
|
||||
/// ident by whitch this is imported into local scope.
|
||||
/// TODO: make this offset-independent.
|
||||
pub(crate) import_name: Option<LocalSyntaxPtr>,
|
||||
pub(crate) import: Option<NamedImport>,
|
||||
}
|
||||
|
||||
// #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
|
@ -150,55 +232,49 @@ pub(crate) struct Resolution {
|
|||
// values: Option<T>,
|
||||
// }
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
struct ModuleItem {
|
||||
ptr: LocalSyntaxPtr,
|
||||
name: SmolStr,
|
||||
kind: SyntaxKind,
|
||||
vis: Vis,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
enum Vis {
|
||||
// Priv,
|
||||
Other,
|
||||
}
|
||||
|
||||
impl InputModuleItems {
|
||||
fn new<'a>(items: impl Iterator<Item = ast::ModuleItem<'a>>) -> InputModuleItems {
|
||||
fn new<'a>(
|
||||
file_items: &FileItems,
|
||||
items: impl Iterator<Item = ast::ModuleItem<'a>>,
|
||||
) -> InputModuleItems {
|
||||
let mut res = InputModuleItems::default();
|
||||
for item in items {
|
||||
res.add_item(item);
|
||||
res.add_item(file_items, item);
|
||||
}
|
||||
res
|
||||
}
|
||||
|
||||
fn add_item(&mut self, item: ast::ModuleItem) -> Option<()> {
|
||||
fn add_item(&mut self, file_items: &FileItems, item: ast::ModuleItem) -> Option<()> {
|
||||
match item {
|
||||
ast::ModuleItem::StructDef(it) => self.items.push(ModuleItem::new(it)?),
|
||||
ast::ModuleItem::EnumDef(it) => self.items.push(ModuleItem::new(it)?),
|
||||
ast::ModuleItem::FnDef(it) => self.items.push(ModuleItem::new(it)?),
|
||||
ast::ModuleItem::TraitDef(it) => self.items.push(ModuleItem::new(it)?),
|
||||
ast::ModuleItem::TypeDef(it) => self.items.push(ModuleItem::new(it)?),
|
||||
ast::ModuleItem::StructDef(it) => self.items.push(ModuleItem::new(file_items, it)?),
|
||||
ast::ModuleItem::EnumDef(it) => self.items.push(ModuleItem::new(file_items, it)?),
|
||||
ast::ModuleItem::FnDef(it) => self.items.push(ModuleItem::new(file_items, it)?),
|
||||
ast::ModuleItem::TraitDef(it) => self.items.push(ModuleItem::new(file_items, it)?),
|
||||
ast::ModuleItem::TypeDef(it) => self.items.push(ModuleItem::new(file_items, it)?),
|
||||
ast::ModuleItem::ImplItem(_) => {
|
||||
// impls don't define items
|
||||
}
|
||||
ast::ModuleItem::UseItem(it) => self.add_use_item(it),
|
||||
ast::ModuleItem::UseItem(it) => self.add_use_item(file_items, it),
|
||||
ast::ModuleItem::ExternCrateItem(_) => {
|
||||
// TODO
|
||||
}
|
||||
ast::ModuleItem::ConstDef(it) => self.items.push(ModuleItem::new(it)?),
|
||||
ast::ModuleItem::StaticDef(it) => self.items.push(ModuleItem::new(it)?),
|
||||
ast::ModuleItem::Module(it) => self.items.push(ModuleItem::new(it)?),
|
||||
ast::ModuleItem::ConstDef(it) => self.items.push(ModuleItem::new(file_items, it)?),
|
||||
ast::ModuleItem::StaticDef(it) => self.items.push(ModuleItem::new(file_items, it)?),
|
||||
ast::ModuleItem::Module(it) => self.items.push(ModuleItem::new(file_items, it)?),
|
||||
}
|
||||
Some(())
|
||||
}
|
||||
|
||||
fn add_use_item(&mut self, item: ast::UseItem) {
|
||||
Path::expand_use_item(item, |path, ptr| {
|
||||
let kind = match ptr {
|
||||
fn add_use_item(&mut self, file_items: &FileItems, item: ast::UseItem) {
|
||||
let file_item_id = file_items.id_of(item.syntax());
|
||||
let start_offset = item.syntax().range().start();
|
||||
Path::expand_use_item(item, |path, range| {
|
||||
let kind = match range {
|
||||
None => ImportKind::Glob,
|
||||
Some(ptr) => ImportKind::Named(ptr),
|
||||
Some(range) => ImportKind::Named(NamedImport {
|
||||
file_item_id,
|
||||
relative_range: range - start_offset,
|
||||
}),
|
||||
};
|
||||
self.imports.push(Import { kind, path })
|
||||
})
|
||||
|
@ -206,13 +282,13 @@ impl InputModuleItems {
|
|||
}
|
||||
|
||||
impl ModuleItem {
|
||||
fn new<'a>(item: impl ast::NameOwner<'a>) -> Option<ModuleItem> {
|
||||
fn new<'a>(file_items: &FileItems, item: impl ast::NameOwner<'a>) -> Option<ModuleItem> {
|
||||
let name = item.name()?.text();
|
||||
let ptr = LocalSyntaxPtr::new(item.syntax());
|
||||
let kind = item.syntax().kind();
|
||||
let vis = Vis::Other;
|
||||
let id = file_items.id_of(item.syntax());
|
||||
let res = ModuleItem {
|
||||
ptr,
|
||||
id,
|
||||
name,
|
||||
kind,
|
||||
vis,
|
||||
|
@ -252,12 +328,12 @@ where
|
|||
|
||||
for import in input.imports.iter() {
|
||||
if let Some(name) = import.path.segments.iter().last() {
|
||||
if let ImportKind::Named(ptr) = import.kind {
|
||||
if let ImportKind::Named(import) = import.kind {
|
||||
module_items.items.insert(
|
||||
name.clone(),
|
||||
Resolution {
|
||||
def_id: None,
|
||||
import_name: Some(ptr),
|
||||
import: Some(import),
|
||||
},
|
||||
);
|
||||
}
|
||||
|
@ -269,12 +345,14 @@ where
|
|||
// handle submodules separatelly
|
||||
continue;
|
||||
}
|
||||
let ptr = item.ptr.into_global(file_id);
|
||||
let def_loc = DefLoc::Item { ptr };
|
||||
let def_loc = DefLoc::Item {
|
||||
file_id,
|
||||
id: item.id,
|
||||
};
|
||||
let def_id = self.db.id_maps().def_id(def_loc);
|
||||
let resolution = Resolution {
|
||||
def_id: Some(def_id),
|
||||
import_name: None,
|
||||
import: None,
|
||||
};
|
||||
module_items.items.insert(item.name.clone(), resolution);
|
||||
}
|
||||
|
@ -287,7 +365,7 @@ where
|
|||
let def_id = self.db.id_maps().def_id(def_loc);
|
||||
let resolution = Resolution {
|
||||
def_id: Some(def_id),
|
||||
import_name: None,
|
||||
import: None,
|
||||
};
|
||||
module_items.items.insert(name, resolution);
|
||||
}
|
||||
|
@ -341,7 +419,7 @@ where
|
|||
self.update(module_id, |items| {
|
||||
let res = Resolution {
|
||||
def_id: Some(def_id),
|
||||
import_name: Some(ptr),
|
||||
import: Some(ptr),
|
||||
};
|
||||
items.items.insert(name.clone(), res);
|
||||
})
|
||||
|
@ -452,10 +530,11 @@ mod tests {
|
|||
let events = db.log_executed(|| {
|
||||
db._item_map(source_root).unwrap();
|
||||
});
|
||||
// assert!(
|
||||
// !format!("{:?}", events).contains("_item_map"),
|
||||
// "{:#?}", events
|
||||
// )
|
||||
assert!(
|
||||
!format!("{:?}", events).contains("_item_map"),
|
||||
"{:#?}",
|
||||
events
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
use ra_syntax::{SmolStr, ast, AstNode};
|
||||
|
||||
use crate::syntax_ptr::LocalSyntaxPtr;
|
||||
use ra_syntax::{SmolStr, ast, AstNode, TextRange};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub(crate) struct Path {
|
||||
|
@ -18,10 +16,7 @@ pub(crate) enum PathKind {
|
|||
|
||||
impl Path {
|
||||
/// Calls `cb` with all paths, represented by this use item.
|
||||
pub(crate) fn expand_use_item(
|
||||
item: ast::UseItem,
|
||||
mut cb: impl FnMut(Path, Option<LocalSyntaxPtr>),
|
||||
) {
|
||||
pub(crate) fn expand_use_item(item: ast::UseItem, mut cb: impl FnMut(Path, Option<TextRange>)) {
|
||||
if let Some(tree) = item.use_tree() {
|
||||
expand_use_tree(None, tree, &mut cb);
|
||||
}
|
||||
|
@ -77,7 +72,7 @@ impl Path {
|
|||
fn expand_use_tree(
|
||||
prefix: Option<Path>,
|
||||
tree: ast::UseTree,
|
||||
cb: &mut impl FnMut(Path, Option<LocalSyntaxPtr>),
|
||||
cb: &mut impl FnMut(Path, Option<TextRange>),
|
||||
) {
|
||||
if let Some(use_tree_list) = tree.use_tree_list() {
|
||||
let prefix = match tree.path() {
|
||||
|
@ -93,13 +88,13 @@ fn expand_use_tree(
|
|||
} else {
|
||||
if let Some(ast_path) = tree.path() {
|
||||
if let Some(path) = convert_path(prefix, ast_path) {
|
||||
let ptr = if tree.has_star() {
|
||||
let range = if tree.has_star() {
|
||||
None
|
||||
} else {
|
||||
let ptr = LocalSyntaxPtr::new(ast_path.segment().unwrap().syntax());
|
||||
Some(ptr)
|
||||
let range = ast_path.segment().unwrap().syntax().range();
|
||||
Some(range)
|
||||
};
|
||||
cb(path, ptr)
|
||||
cb(path, range)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,6 +8,8 @@ use std::{
|
|||
use rustc_hash::FxHashMap;
|
||||
|
||||
use crate::{
|
||||
FileId,
|
||||
descriptors::FileItemId,
|
||||
descriptors::module::ModuleId,
|
||||
syntax_ptr::SyntaxPtr,
|
||||
input::SourceRootId,
|
||||
|
@ -102,7 +104,8 @@ pub(crate) enum DefLoc {
|
|||
source_root: SourceRootId,
|
||||
},
|
||||
Item {
|
||||
ptr: SyntaxPtr,
|
||||
file_id: FileId,
|
||||
id: FileItemId,
|
||||
},
|
||||
}
|
||||
|
||||
|
|
|
@ -62,11 +62,6 @@ impl LocalSyntaxPtr {
|
|||
local: self,
|
||||
}
|
||||
}
|
||||
|
||||
// Seems unfortunate to expose
|
||||
pub(crate) fn range(self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
Loading…
Add table
Reference in a new issue