mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-26 04:53:34 +00:00
dispatch acros roots
This commit is contained in:
parent
2f2feef9af
commit
b04c14d4ad
5 changed files with 180 additions and 75 deletions
|
@ -17,8 +17,8 @@ use libsyntax2::{
|
|||
use {
|
||||
FileId, FileResolver, Query, Diagnostic, SourceChange, SourceFileEdit, Position, FileSystemEdit,
|
||||
JobToken, CrateGraph, CrateId,
|
||||
module_map::Problem,
|
||||
roots::SourceRoot,
|
||||
module_map::{ModuleMap, Problem},
|
||||
roots::{SourceRoot, ReadonlySourceRoot, WritableSourceRoot},
|
||||
};
|
||||
|
||||
#[derive(Debug)]
|
||||
|
@ -57,6 +57,10 @@ impl AnalysisHostImpl {
|
|||
}
|
||||
self.data_mut().crate_graph = graph;
|
||||
}
|
||||
pub fn set_libraries(&mut self, libs: impl Iterator<Item=impl Iterator<Item=(FileId, String)>>) {
|
||||
let libs = libs.map(ReadonlySourceRoot::new).collect::<Vec<_>>();
|
||||
self.data_mut().libs = Arc::new(libs);
|
||||
}
|
||||
fn data_mut(&mut self) -> &mut WorldData {
|
||||
Arc::make_mut(&mut self.data)
|
||||
}
|
||||
|
@ -85,19 +89,33 @@ impl Clone for AnalysisImpl {
|
|||
}
|
||||
|
||||
impl AnalysisImpl {
|
||||
fn root(&self, file_id: FileId) -> &SourceRoot {
|
||||
if self.data.root.contains(file_id) {
|
||||
return &self.data.root;
|
||||
}
|
||||
self.data.libs.iter().find(|it| it.contains(file_id)).unwrap()
|
||||
}
|
||||
pub fn file_syntax(&self, file_id: FileId) -> &File {
|
||||
self.data.root.syntax(file_id)
|
||||
self.root(file_id).syntax(file_id)
|
||||
}
|
||||
pub fn file_line_index(&self, file_id: FileId) -> &LineIndex {
|
||||
self.data.root.lines(file_id)
|
||||
self.root(file_id).lines(file_id)
|
||||
}
|
||||
pub fn world_symbols(&self, query: Query, token: &JobToken) -> Vec<(FileId, FileSymbol)> {
|
||||
pub fn world_symbols(&self, query: Query, token: &JobToken) -> Vec<(FileId, FileSymbol)> {
|
||||
self.reindex();
|
||||
query.search(&self.data.root.symbols(), token)
|
||||
let mut buf = Vec::new();
|
||||
if query.libs {
|
||||
self.data.libs.iter()
|
||||
.for_each(|it| it.symbols(&mut buf));
|
||||
} else {
|
||||
self.data.root.symbols(&mut buf);
|
||||
}
|
||||
query.search(&buf, token)
|
||||
|
||||
}
|
||||
pub fn parent_module(&self, id: FileId) -> Vec<(FileId, FileSymbol)> {
|
||||
let module_map = self.data.root.module_map();
|
||||
let id = module_map.file2module(id);
|
||||
pub fn parent_module(&self, file_id: FileId) -> Vec<(FileId, FileSymbol)> {
|
||||
let module_map = self.root(file_id).module_map();
|
||||
let id = module_map.file2module(file_id);
|
||||
module_map
|
||||
.parent_modules(
|
||||
id,
|
||||
|
@ -117,12 +135,12 @@ impl AnalysisImpl {
|
|||
.collect()
|
||||
}
|
||||
|
||||
pub fn crate_for(&self, id: FileId) -> Vec<CrateId> {
|
||||
let module_map = self.data.root.module_map();
|
||||
pub fn crate_for(&self, file_id: FileId) -> Vec<CrateId> {
|
||||
let module_map = self.root(file_id).module_map();
|
||||
let crate_graph = &self.data.crate_graph;
|
||||
let mut res = Vec::new();
|
||||
let mut work = VecDeque::new();
|
||||
work.push_back(id);
|
||||
work.push_back(file_id);
|
||||
let mut visited = HashSet::new();
|
||||
while let Some(id) = work.pop_front() {
|
||||
if let Some(crate_id) = crate_graph.crate_id_for_crate_root(id) {
|
||||
|
@ -148,11 +166,13 @@ impl AnalysisImpl {
|
|||
}
|
||||
pub fn approximately_resolve_symbol(
|
||||
&self,
|
||||
id: FileId,
|
||||
file_id: FileId,
|
||||
offset: TextUnit,
|
||||
token: &JobToken,
|
||||
) -> Vec<(FileId, FileSymbol)> {
|
||||
let file = self.file_syntax(id);
|
||||
let root = self.root(file_id);
|
||||
let module_map = root.module_map();
|
||||
let file = root.syntax(file_id);
|
||||
let syntax = file.syntax();
|
||||
if let Some(name_ref) = find_node_at_offset::<ast::NameRef>(syntax, offset) {
|
||||
return self.index_resolve(name_ref, token);
|
||||
|
@ -160,7 +180,7 @@ impl AnalysisImpl {
|
|||
if let Some(name) = find_node_at_offset::<ast::Name>(syntax, offset) {
|
||||
if let Some(module) = name.syntax().parent().and_then(ast::Module::cast) {
|
||||
if module.has_semi() {
|
||||
let file_ids = self.resolve_module(id, module);
|
||||
let file_ids = self.resolve_module(module_map, file_id, module);
|
||||
|
||||
let res = file_ids.into_iter().map(|id| {
|
||||
let name = module.name()
|
||||
|
@ -182,13 +202,16 @@ impl AnalysisImpl {
|
|||
}
|
||||
|
||||
pub fn diagnostics(&self, file_id: FileId) -> Vec<Diagnostic> {
|
||||
let syntax = self.file_syntax(file_id);
|
||||
let root = self.root(file_id);
|
||||
let module_map = root.module_map();
|
||||
let syntax = root.syntax(file_id);
|
||||
|
||||
let mut res = libeditor::diagnostics(&syntax)
|
||||
.into_iter()
|
||||
.map(|d| Diagnostic { range: d.range, message: d.msg, fix: None })
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
self.data.root.module_map().problems(
|
||||
module_map.problems(
|
||||
file_id,
|
||||
&*self.file_resolver,
|
||||
&|file_id| self.file_syntax(file_id),
|
||||
|
@ -257,13 +280,12 @@ impl AnalysisImpl {
|
|||
self.world_symbols(query, token)
|
||||
}
|
||||
|
||||
fn resolve_module(&self, id: FileId, module: ast::Module) -> Vec<FileId> {
|
||||
fn resolve_module(&self, module_map: &ModuleMap, file_id: FileId, module: ast::Module) -> Vec<FileId> {
|
||||
let name = match module.name() {
|
||||
Some(name) => name.text(),
|
||||
None => return Vec::new(),
|
||||
};
|
||||
let module_map = self.data.root.module_map();
|
||||
let id = module_map.file2module(id);
|
||||
let id = module_map.file2module(file_id);
|
||||
module_map
|
||||
.child_module_by_name(
|
||||
id, name.as_str(),
|
||||
|
@ -285,7 +307,8 @@ impl AnalysisImpl {
|
|||
#[derive(Clone, Default, Debug)]
|
||||
struct WorldData {
|
||||
crate_graph: CrateGraph,
|
||||
root: SourceRoot,
|
||||
root: WritableSourceRoot,
|
||||
libs: Arc<Vec<ReadonlySourceRoot>>,
|
||||
}
|
||||
|
||||
impl SourceChange {
|
||||
|
|
|
@ -68,6 +68,9 @@ impl AnalysisHost {
|
|||
pub fn set_crate_graph(&mut self, graph: CrateGraph) {
|
||||
self.imp.set_crate_graph(graph)
|
||||
}
|
||||
pub fn set_libraries(&mut self, libs: impl Iterator<Item=impl Iterator<Item=(FileId, String)>>) {
|
||||
self.imp.set_libraries(libs)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
@ -114,6 +117,7 @@ pub struct Query {
|
|||
query: String,
|
||||
lowercased: String,
|
||||
only_types: bool,
|
||||
libs: bool,
|
||||
exact: bool,
|
||||
limit: usize,
|
||||
}
|
||||
|
@ -125,6 +129,7 @@ impl Query {
|
|||
query,
|
||||
lowercased,
|
||||
only_types: false,
|
||||
libs: false,
|
||||
exact: false,
|
||||
limit: usize::max_value()
|
||||
}
|
||||
|
@ -132,6 +137,9 @@ impl Query {
|
|||
pub fn only_types(&mut self) {
|
||||
self.only_types = true;
|
||||
}
|
||||
pub fn libs(&mut self) {
|
||||
self.libs = true;
|
||||
}
|
||||
pub fn exact(&mut self) {
|
||||
self.exact = true;
|
||||
}
|
||||
|
|
|
@ -56,6 +56,10 @@ pub enum Problem {
|
|||
}
|
||||
|
||||
impl ModuleMap {
|
||||
pub fn new() -> ModuleMap {
|
||||
Default::default()
|
||||
}
|
||||
|
||||
pub fn update_file(&mut self, file: FileId, change_kind: ChangeKind) {
|
||||
self.state.get_mut().changes.push((file, change_kind));
|
||||
}
|
||||
|
|
|
@ -13,16 +13,24 @@ use libsyntax2::File;
|
|||
use {
|
||||
FileId,
|
||||
module_map::{ModuleMap, ChangeKind},
|
||||
symbol_index::FileSymbols,
|
||||
symbol_index::SymbolIndex,
|
||||
};
|
||||
|
||||
pub(crate) trait SourceRoot {
|
||||
fn contains(&self, file_id: FileId) -> bool;
|
||||
fn module_map(&self) -> &ModuleMap;
|
||||
fn lines(&self, file_id: FileId) -> &LineIndex;
|
||||
fn syntax(&self, file_id: FileId) -> &File;
|
||||
fn symbols<'a>(&'a self, acc: &mut Vec<&'a SymbolIndex>);
|
||||
}
|
||||
|
||||
#[derive(Clone, Default, Debug)]
|
||||
pub(crate) struct SourceRoot {
|
||||
file_map: HashMap<FileId, Arc<(FileData, OnceCell<FileSymbols>)>>,
|
||||
pub(crate) struct WritableSourceRoot {
|
||||
file_map: HashMap<FileId, Arc<(FileData, OnceCell<SymbolIndex>)>>,
|
||||
module_map: ModuleMap,
|
||||
}
|
||||
|
||||
impl SourceRoot {
|
||||
impl WritableSourceRoot {
|
||||
pub fn update(&mut self, file_id: FileId, text: Option<String>) {
|
||||
let change_kind = if self.file_map.remove(&file_id).is_some() {
|
||||
if text.is_some() {
|
||||
|
@ -40,31 +48,6 @@ impl SourceRoot {
|
|||
self.file_map.insert(file_id, Arc::new((file_data, Default::default())));
|
||||
}
|
||||
}
|
||||
pub fn module_map(&self) -> &ModuleMap {
|
||||
&self.module_map
|
||||
}
|
||||
pub fn lines(&self, file_id: FileId) -> &LineIndex {
|
||||
let data = self.data(file_id);
|
||||
data.lines.get_or_init(|| LineIndex::new(&data.text))
|
||||
}
|
||||
pub fn syntax(&self, file_id: FileId) -> &File {
|
||||
let data = self.data(file_id);
|
||||
let text = &data.text;
|
||||
let syntax = &data.syntax;
|
||||
match panic::catch_unwind(panic::AssertUnwindSafe(|| syntax.get_or_init(|| File::parse(text)))) {
|
||||
Ok(file) => file,
|
||||
Err(err) => {
|
||||
error!("Parser paniced on:\n------\n{}\n------\n", &data.text);
|
||||
panic::resume_unwind(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
pub(crate) fn symbols(&self) -> Vec<&FileSymbols> {
|
||||
self.file_map
|
||||
.iter()
|
||||
.map(|(&file_id, data)| symbols(file_id, data))
|
||||
.collect()
|
||||
}
|
||||
pub fn reindex(&self) {
|
||||
let now = Instant::now();
|
||||
self.file_map
|
||||
|
@ -83,9 +66,31 @@ impl SourceRoot {
|
|||
}
|
||||
}
|
||||
|
||||
fn symbols(file_id: FileId, (data, symbols): &(FileData, OnceCell<FileSymbols>)) -> &FileSymbols {
|
||||
impl SourceRoot for WritableSourceRoot {
|
||||
fn contains(&self, file_id: FileId) -> bool {
|
||||
self.file_map.contains_key(&file_id)
|
||||
}
|
||||
fn module_map(&self) -> &ModuleMap {
|
||||
&self.module_map
|
||||
}
|
||||
fn lines(&self, file_id: FileId) -> &LineIndex {
|
||||
self.data(file_id).lines()
|
||||
}
|
||||
fn syntax(&self, file_id: FileId) -> &File {
|
||||
self.data(file_id).syntax()
|
||||
}
|
||||
fn symbols<'a>(&'a self, acc: &mut Vec<&'a SymbolIndex>) {
|
||||
acc.extend(
|
||||
self.file_map
|
||||
.iter()
|
||||
.map(|(&file_id, data)| symbols(file_id, data))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fn symbols(file_id: FileId, (data, symbols): &(FileData, OnceCell<SymbolIndex>)) -> &SymbolIndex {
|
||||
let syntax = data.syntax_transient();
|
||||
symbols.get_or_init(|| FileSymbols::new(file_id, &syntax))
|
||||
symbols.get_or_init(|| SymbolIndex::for_file(file_id, syntax))
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
@ -103,19 +108,77 @@ impl FileData {
|
|||
lines: OnceCell::new(),
|
||||
}
|
||||
}
|
||||
fn lines(&self) -> &LineIndex {
|
||||
self.lines.get_or_init(|| LineIndex::new(&self.text))
|
||||
}
|
||||
fn syntax(&self) -> &File {
|
||||
let text = &self.text;
|
||||
let syntax = &self.syntax;
|
||||
match panic::catch_unwind(panic::AssertUnwindSafe(|| syntax.get_or_init(|| File::parse(text)))) {
|
||||
Ok(file) => file,
|
||||
Err(err) => {
|
||||
error!("Parser paniced on:\n------\n{}\n------\n", text);
|
||||
panic::resume_unwind(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
fn syntax_transient(&self) -> File {
|
||||
self.syntax.get().map(|s| s.clone())
|
||||
.unwrap_or_else(|| File::parse(&self.text))
|
||||
}
|
||||
}
|
||||
|
||||
// #[derive(Clone, Default, Debug)]
|
||||
// pub(crate) struct ReadonlySourceRoot {
|
||||
// data: Arc<ReadonlySourceRoot>
|
||||
// }
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct ReadonlySourceRoot {
|
||||
symbol_index: SymbolIndex,
|
||||
file_map: HashMap<FileId, FileData>,
|
||||
module_map: ModuleMap,
|
||||
}
|
||||
|
||||
// #[derive(Clone, Default, Debug)]
|
||||
// pub(crate) struct ReadonlySourceRootInner {
|
||||
// file_map: HashMap<FileId, FileData>,
|
||||
// module_map: ModuleMap,
|
||||
// }
|
||||
impl ReadonlySourceRoot {
|
||||
pub fn new(files: impl Iterator<Item=(FileId, String)>) -> ReadonlySourceRoot {
|
||||
let mut module_map = ModuleMap::new();
|
||||
let file_map: HashMap<FileId, FileData> = files
|
||||
.map(|(id, text)| {
|
||||
module_map.update_file(id, ChangeKind::Insert);
|
||||
(id, FileData::new(text))
|
||||
})
|
||||
.collect();
|
||||
let symbol_index = SymbolIndex::for_files(
|
||||
file_map.par_iter().map(|(&file_id, file_data)| {
|
||||
(file_id, file_data.syntax_transient())
|
||||
})
|
||||
);
|
||||
|
||||
ReadonlySourceRoot {
|
||||
symbol_index,
|
||||
file_map,
|
||||
module_map,
|
||||
}
|
||||
}
|
||||
|
||||
fn data(&self, file_id: FileId) -> &FileData {
|
||||
match self.file_map.get(&file_id) {
|
||||
Some(data) => data,
|
||||
None => panic!("unknown file: {:?}", file_id),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl SourceRoot for ReadonlySourceRoot {
|
||||
fn contains(&self, file_id: FileId) -> bool {
|
||||
self.file_map.contains_key(&file_id)
|
||||
}
|
||||
fn module_map(&self) -> &ModuleMap {
|
||||
&self.module_map
|
||||
}
|
||||
fn lines(&self, file_id: FileId) -> &LineIndex {
|
||||
self.data(file_id).lines()
|
||||
}
|
||||
fn syntax(&self, file_id: FileId) -> &File {
|
||||
self.data(file_id).syntax()
|
||||
}
|
||||
fn symbols<'a>(&'a self, acc: &mut Vec<&'a SymbolIndex>) {
|
||||
acc.push(&self.symbol_index)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,39 +4,46 @@ use libsyntax2::{
|
|||
SyntaxKind::{self, *},
|
||||
};
|
||||
use fst::{self, Streamer};
|
||||
use rayon::prelude::*;
|
||||
use {Query, FileId, JobToken};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct FileSymbols {
|
||||
pub(crate) struct SymbolIndex {
|
||||
symbols: Vec<(FileId, FileSymbol)>,
|
||||
map: fst::Map,
|
||||
}
|
||||
|
||||
impl FileSymbols {
|
||||
pub(crate) fn new(file_id: FileId, file: &File) -> FileSymbols {
|
||||
let mut symbols = file_symbols(file)
|
||||
.into_iter()
|
||||
.map(|s| (s.name.as_str().to_lowercase(), s))
|
||||
impl SymbolIndex {
|
||||
pub(crate) fn for_files(files: impl ParallelIterator<Item=(FileId, File)>) -> SymbolIndex {
|
||||
let mut symbols = files
|
||||
.flat_map(|(file_id, file)| {
|
||||
file_symbols(&file)
|
||||
.into_iter()
|
||||
.map(move |symbol| {
|
||||
(symbol.name.as_str().to_lowercase(), (file_id, symbol))
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
symbols.sort_by(|s1, s2| s1.0.cmp(&s2.0));
|
||||
symbols.par_sort_by(|s1, s2| s1.0.cmp(&s2.0));
|
||||
symbols.dedup_by(|s1, s2| s1.0 == s2.0);
|
||||
let (names, symbols): (Vec<String>, Vec<(FileId, FileSymbol)>) =
|
||||
symbols.into_iter()
|
||||
.map(|(name, symbol)| (name, (file_id, symbol)))
|
||||
.unzip();
|
||||
|
||||
symbols.into_iter().unzip();
|
||||
let map = fst::Map::from_iter(
|
||||
names.into_iter().zip(0u64..)
|
||||
).unwrap();
|
||||
FileSymbols { symbols, map }
|
||||
SymbolIndex { symbols, map }
|
||||
}
|
||||
|
||||
pub(crate) fn for_file(file_id: FileId, file: File) -> SymbolIndex {
|
||||
SymbolIndex::for_files(::rayon::iter::once((file_id, file)))
|
||||
}
|
||||
}
|
||||
|
||||
impl Query {
|
||||
pub(crate) fn search(
|
||||
mut self,
|
||||
indices: &[&FileSymbols],
|
||||
indices: &[&SymbolIndex],
|
||||
token: &JobToken,
|
||||
) -> Vec<(FileId, FileSymbol)> {
|
||||
|
||||
|
|
Loading…
Reference in a new issue