mirror of
				https://github.com/rust-lang/rust-analyzer.git
				synced 2025-11-03 13:13:18 +00:00 
			
		
		
		
	add crate graph
This commit is contained in:
		
							parent
							
								
									7a5bc94774
								
							
						
					
					
						commit
						f2772e29ae
					
				@ -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…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user