mirror of
https://github.com/rust-lang/rust-analyzer
synced 2025-01-12 21:28:51 +00:00
add crate graph
This commit is contained in:
parent
7a5bc94774
commit
f2772e29ae
4 changed files with 131 additions and 15 deletions
|
@ -5,7 +5,7 @@ use std::{
|
||||||
},
|
},
|
||||||
fmt,
|
fmt,
|
||||||
time::Instant,
|
time::Instant,
|
||||||
collections::HashMap,
|
collections::{HashMap, HashSet, VecDeque},
|
||||||
panic,
|
panic,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -23,7 +23,7 @@ use {
|
||||||
module_map::Problem,
|
module_map::Problem,
|
||||||
symbol_index::FileSymbols,
|
symbol_index::FileSymbols,
|
||||||
module_map::{ModuleMap, ChangeKind},
|
module_map::{ModuleMap, ChangeKind},
|
||||||
JobToken,
|
JobToken, CrateGraph, CrateId,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -37,7 +37,6 @@ impl AnalysisHostImpl {
|
||||||
data: Arc::new(WorldData::default()),
|
data: Arc::new(WorldData::default()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn analysis(
|
pub fn analysis(
|
||||||
&self,
|
&self,
|
||||||
file_resolver: Arc<dyn FileResolver>,
|
file_resolver: Arc<dyn FileResolver>,
|
||||||
|
@ -48,7 +47,6 @@ impl AnalysisHostImpl {
|
||||||
data: self.data.clone(),
|
data: self.data.clone(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn change_files(&mut self, changes: &mut dyn Iterator<Item=(FileId, Option<String>)>) {
|
pub fn change_files(&mut self, changes: &mut dyn Iterator<Item=(FileId, Option<String>)>) {
|
||||||
let data = self.data_mut();
|
let data = self.data_mut();
|
||||||
for (file_id, text) in changes {
|
for (file_id, text) in changes {
|
||||||
|
@ -71,7 +69,15 @@ impl AnalysisHostImpl {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
pub fn set_crate_graph(&mut self, graph: CrateGraph) {
|
||||||
|
let mut visited = HashSet::new();
|
||||||
|
for &file_id in graph.crate_roots.values() {
|
||||||
|
if !visited.insert(file_id) {
|
||||||
|
panic!("duplicate crate root: {:?}", file_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.data_mut().crate_graph = graph;
|
||||||
|
}
|
||||||
fn data_mut(&mut self) -> &mut WorldData {
|
fn data_mut(&mut self) -> &mut WorldData {
|
||||||
Arc::make_mut(&mut self.data)
|
Arc::make_mut(&mut self.data)
|
||||||
}
|
}
|
||||||
|
@ -145,6 +151,33 @@ impl AnalysisImpl {
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn crate_root(&self, id: FileId) -> Vec<CrateId> {
|
||||||
|
let module_map = &self.data.module_map;
|
||||||
|
let crate_graph = &self.data.crate_graph;
|
||||||
|
let mut res = Vec::new();
|
||||||
|
let mut work = VecDeque::new();
|
||||||
|
work.push_back(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) {
|
||||||
|
res.push(crate_id);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let mid = module_map.file2module(id);
|
||||||
|
let parents = module_map
|
||||||
|
.parent_module_ids(
|
||||||
|
mid,
|
||||||
|
&*self.file_resolver,
|
||||||
|
&|file_id| self.file_syntax(file_id),
|
||||||
|
)
|
||||||
|
.into_iter()
|
||||||
|
.map(|id| module_map.module2file(id))
|
||||||
|
.filter(|&id| visited.insert(id));
|
||||||
|
work.extend(parents);
|
||||||
|
}
|
||||||
|
res
|
||||||
|
}
|
||||||
|
|
||||||
pub fn approximately_resolve_symbol(
|
pub fn approximately_resolve_symbol(
|
||||||
&self,
|
&self,
|
||||||
id: FileId,
|
id: FileId,
|
||||||
|
@ -295,6 +328,7 @@ impl AnalysisImpl {
|
||||||
|
|
||||||
#[derive(Clone, Default, Debug)]
|
#[derive(Clone, Default, Debug)]
|
||||||
struct WorldData {
|
struct WorldData {
|
||||||
|
crate_graph: CrateGraph,
|
||||||
file_map: HashMap<FileId, Arc<FileData>>,
|
file_map: HashMap<FileId, Arc<FileData>>,
|
||||||
module_map: ModuleMap,
|
module_map: ModuleMap,
|
||||||
}
|
}
|
||||||
|
@ -356,3 +390,12 @@ impl SourceChange {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl CrateGraph {
|
||||||
|
fn crate_id_for_crate_root(&self, file_id: FileId) -> Option<CrateId> {
|
||||||
|
let (&crate_id, _) = self.crate_roots
|
||||||
|
.iter()
|
||||||
|
.find(|(_crate_id, &root_id)| root_id == file_id)?;
|
||||||
|
Some(crate_id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -15,7 +15,10 @@ mod module_map;
|
||||||
mod imp;
|
mod imp;
|
||||||
mod job;
|
mod job;
|
||||||
|
|
||||||
use std::sync::Arc;
|
use std::{
|
||||||
|
sync::Arc,
|
||||||
|
collections::HashMap,
|
||||||
|
};
|
||||||
|
|
||||||
use relative_path::{RelativePath, RelativePathBuf};
|
use relative_path::{RelativePath, RelativePathBuf};
|
||||||
use libsyntax2::{File, TextRange, TextUnit, AtomEdit};
|
use libsyntax2::{File, TextRange, TextUnit, AtomEdit};
|
||||||
|
@ -30,6 +33,14 @@ pub use job::{JobToken, JobHandle};
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
pub struct FileId(pub u32);
|
pub struct FileId(pub u32);
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
|
pub struct CrateId(pub u32);
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Default)]
|
||||||
|
pub struct CrateGraph {
|
||||||
|
pub crate_roots: HashMap<CrateId, FileId>,
|
||||||
|
}
|
||||||
|
|
||||||
pub trait FileResolver: Send + Sync + 'static {
|
pub trait FileResolver: Send + Sync + 'static {
|
||||||
fn file_stem(&self, id: FileId) -> String;
|
fn file_stem(&self, id: FileId) -> String;
|
||||||
fn resolve(&self, id: FileId, path: &RelativePath) -> Option<FileId>;
|
fn resolve(&self, id: FileId, path: &RelativePath) -> Option<FileId>;
|
||||||
|
@ -53,6 +64,9 @@ impl AnalysisHost {
|
||||||
pub fn change_files(&mut self, mut changes: impl Iterator<Item=(FileId, Option<String>)>) {
|
pub fn change_files(&mut self, mut changes: impl Iterator<Item=(FileId, Option<String>)>) {
|
||||||
self.imp.change_files(&mut changes)
|
self.imp.change_files(&mut changes)
|
||||||
}
|
}
|
||||||
|
pub fn set_crate_graph(&mut self, graph: CrateGraph) {
|
||||||
|
self.imp.set_crate_graph(graph)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -168,6 +182,9 @@ impl Analysis {
|
||||||
pub fn parent_module(&self, file_id: FileId) -> Vec<(FileId, FileSymbol)> {
|
pub fn parent_module(&self, file_id: FileId) -> Vec<(FileId, FileSymbol)> {
|
||||||
self.imp.parent_module(file_id)
|
self.imp.parent_module(file_id)
|
||||||
}
|
}
|
||||||
|
pub fn crate_root(&self, file_id: FileId) -> Vec<CrateId> {
|
||||||
|
self.imp.crate_root(file_id)
|
||||||
|
}
|
||||||
pub fn runnables(&self, file_id: FileId) -> Vec<Runnable> {
|
pub fn runnables(&self, file_id: FileId) -> Vec<Runnable> {
|
||||||
let file = self.file_syntax(file_id);
|
let file = self.file_syntax(file_id);
|
||||||
libeditor::runnables(&file)
|
libeditor::runnables(&file)
|
||||||
|
|
|
@ -91,16 +91,38 @@ impl ModuleMap {
|
||||||
file_resolver: &FileResolver,
|
file_resolver: &FileResolver,
|
||||||
syntax_provider: &SyntaxProvider,
|
syntax_provider: &SyntaxProvider,
|
||||||
) -> Vec<(ModuleId, SmolStr, SyntaxNode)> {
|
) -> Vec<(ModuleId, SmolStr, SyntaxNode)> {
|
||||||
let links = self.links(file_resolver, syntax_provider);
|
let mut res = Vec::new();
|
||||||
let res = links
|
self.for_each_parent_link(m, file_resolver, syntax_provider, |link| {
|
||||||
|
res.push(
|
||||||
|
(link.owner, link.name().clone(), link.syntax.clone())
|
||||||
|
)
|
||||||
|
});
|
||||||
|
res
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn parent_module_ids(
|
||||||
|
&self,
|
||||||
|
m: ModuleId,
|
||||||
|
file_resolver: &FileResolver,
|
||||||
|
syntax_provider: &SyntaxProvider,
|
||||||
|
) -> Vec<ModuleId> {
|
||||||
|
let mut res = Vec::new();
|
||||||
|
self.for_each_parent_link(m, file_resolver, syntax_provider, |link| res.push(link.owner));
|
||||||
|
res
|
||||||
|
}
|
||||||
|
|
||||||
|
fn for_each_parent_link(
|
||||||
|
&self,
|
||||||
|
m: ModuleId,
|
||||||
|
file_resolver: &FileResolver,
|
||||||
|
syntax_provider: &SyntaxProvider,
|
||||||
|
f: impl FnMut(&Link)
|
||||||
|
) {
|
||||||
|
self.links(file_resolver, syntax_provider)
|
||||||
.links
|
.links
|
||||||
.iter()
|
.iter()
|
||||||
.filter(move |link| link.points_to.iter().any(|&it| it == m))
|
.filter(move |link| link.points_to.iter().any(|&it| it == m))
|
||||||
.map(|link| {
|
.for_each(f)
|
||||||
(link.owner, link.name().clone(), link.syntax.clone())
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
res
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn problems(
|
pub fn problems(
|
||||||
|
|
|
@ -2,10 +2,13 @@ extern crate libanalysis;
|
||||||
extern crate relative_path;
|
extern crate relative_path;
|
||||||
extern crate test_utils;
|
extern crate test_utils;
|
||||||
|
|
||||||
use std::path::{Path};
|
use std::{
|
||||||
|
collections::HashMap,
|
||||||
|
path::{Path},
|
||||||
|
};
|
||||||
|
|
||||||
use relative_path::RelativePath;
|
use relative_path::RelativePath;
|
||||||
use libanalysis::{AnalysisHost, FileId, FileResolver, JobHandle};
|
use libanalysis::{AnalysisHost, FileId, FileResolver, JobHandle, CrateGraph, CrateId};
|
||||||
use test_utils::assert_eq_dbg;
|
use test_utils::assert_eq_dbg;
|
||||||
|
|
||||||
struct FileMap(&'static [(u32, &'static str)]);
|
struct FileMap(&'static [(u32, &'static str)]);
|
||||||
|
@ -112,3 +115,34 @@ fn test_resolve_parent_module() {
|
||||||
&symbols,
|
&symbols,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_resolve_crate_root() {
|
||||||
|
let mut world = AnalysisHost::new();
|
||||||
|
world.change_file(FileId(1), Some("mod foo;".to_string()));
|
||||||
|
world.change_file(FileId(2), Some("".to_string()));
|
||||||
|
|
||||||
|
let snap = world.analysis(FileMap(&[
|
||||||
|
(1, "/lib.rs"),
|
||||||
|
(2, "/foo.rs"),
|
||||||
|
]));
|
||||||
|
assert!(snap.crate_root(FileId(2)).is_empty());
|
||||||
|
|
||||||
|
let crate_graph = CrateGraph {
|
||||||
|
crate_roots: {
|
||||||
|
let mut m = HashMap::new();
|
||||||
|
m.insert(CrateId(1), FileId(1));
|
||||||
|
m
|
||||||
|
},
|
||||||
|
};
|
||||||
|
world.set_crate_graph(crate_graph);
|
||||||
|
|
||||||
|
let snap = world.analysis(FileMap(&[
|
||||||
|
(1, "/lib.rs"),
|
||||||
|
(2, "/foo.rs"),
|
||||||
|
]));
|
||||||
|
assert_eq!(
|
||||||
|
snap.crate_root(FileId(2)),
|
||||||
|
vec![CrateId(1)],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue