mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-26 13:03:31 +00:00
introduce hir debugging infra
This is to make debugging rust-analyzer easier. The idea is that `dbg!(krate.debug(db))` will print the actual, fuzzy crate name, instead of precise ID. Debug printing infra is a separate thing, to make sure that the actual hir doesn't have access to global information. Do not use `.debug` for `log::` logging: debugging executes queries, and might introduce unneded dependencies to the crate graph
This commit is contained in:
parent
734a43e95a
commit
ef2b84ddf1
11 changed files with 166 additions and 18 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -1060,6 +1060,7 @@ dependencies = [
|
|||
"lsp-server 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lsp-types 0.61.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ra_db 0.1.0",
|
||||
"ra_ide_api 0.1.0",
|
||||
"ra_prof 0.1.0",
|
||||
"ra_project_model 0.1.0",
|
||||
|
|
|
@ -82,6 +82,12 @@ pub struct CyclicDependencies;
|
|||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
pub struct CrateId(pub u32);
|
||||
|
||||
impl CrateId {
|
||||
pub fn shift(self, amount: u32) -> CrateId {
|
||||
CrateId(self.0 + amount)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub enum Edition {
|
||||
Edition2018,
|
||||
|
@ -178,15 +184,19 @@ impl CrateGraph {
|
|||
|
||||
/// Extends this crate graph by adding a complete disjoint second crate
|
||||
/// graph.
|
||||
pub fn extend(&mut self, other: CrateGraph) {
|
||||
///
|
||||
/// The ids of the crates in the `other` graph are shifted by the return
|
||||
/// amount.
|
||||
pub fn extend(&mut self, other: CrateGraph) -> u32 {
|
||||
let start = self.arena.len() as u32;
|
||||
self.arena.extend(other.arena.into_iter().map(|(id, mut data)| {
|
||||
let new_id = CrateId(id.0 + start);
|
||||
let new_id = id.shift(start);
|
||||
for dep in &mut data.dependencies {
|
||||
dep.crate_id = CrateId(dep.crate_id.0 + start);
|
||||
dep.crate_id = dep.crate_id.shift(start);
|
||||
}
|
||||
(new_id, data)
|
||||
}));
|
||||
start
|
||||
}
|
||||
|
||||
fn dfs_find(&self, target: CrateId, from: CrateId, visited: &mut FxHashSet<CrateId>) -> bool {
|
||||
|
|
|
@ -5,6 +5,7 @@ use ra_syntax::{ast, Parse, SmolStr, SyntaxNode};
|
|||
|
||||
use crate::{
|
||||
adt::{EnumData, StructData},
|
||||
debug::HirDebugDatabase,
|
||||
generics::{GenericDef, GenericParams},
|
||||
ids,
|
||||
impl_block::{ImplBlock, ImplSourceMap, ModuleImplBlocks},
|
||||
|
@ -83,7 +84,7 @@ pub trait AstDatabase: InternDatabase {
|
|||
// This database uses `AstDatabase` internally,
|
||||
#[salsa::query_group(DefDatabaseStorage)]
|
||||
#[salsa::requires(AstDatabase)]
|
||||
pub trait DefDatabase: InternDatabase {
|
||||
pub trait DefDatabase: InternDatabase + HirDebugDatabase {
|
||||
#[salsa::invoke(crate::adt::StructData::struct_data_query)]
|
||||
fn struct_data(&self, s: Struct) -> Arc<StructData>;
|
||||
|
||||
|
|
64
crates/ra_hir/src/debug.rs
Normal file
64
crates/ra_hir/src/debug.rs
Normal file
|
@ -0,0 +1,64 @@
|
|||
use std::{cell::Cell, fmt};
|
||||
|
||||
use ra_db::{CrateId, FileId};
|
||||
|
||||
use crate::{db::HirDatabase, Crate, Module, Name};
|
||||
|
||||
impl Crate {
|
||||
pub fn debug(self, db: &impl HirDebugDatabase) -> impl fmt::Debug + '_ {
|
||||
debug_fn(move |fmt| db.debug_crate(self, fmt))
|
||||
}
|
||||
}
|
||||
|
||||
impl Module {
|
||||
pub fn debug(self, db: &impl HirDebugDatabase) -> impl fmt::Debug + '_ {
|
||||
debug_fn(move |fmt| db.debug_module(self, fmt))
|
||||
}
|
||||
}
|
||||
|
||||
pub trait HirDebugHelper: HirDatabase {
|
||||
fn crate_name(&self, _krate: CrateId) -> Option<String> {
|
||||
None
|
||||
}
|
||||
fn file_path(&self, _file_id: FileId) -> Option<String> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub trait HirDebugDatabase {
|
||||
fn debug_crate(&self, krate: Crate, fmt: &mut fmt::Formatter<'_>) -> fmt::Result;
|
||||
fn debug_module(&self, module: Module, fmt: &mut fmt::Formatter<'_>) -> fmt::Result;
|
||||
}
|
||||
|
||||
impl<DB: HirDebugHelper> HirDebugDatabase for DB {
|
||||
fn debug_crate(&self, krate: Crate, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let mut builder = fmt.debug_tuple("Crate");
|
||||
match self.crate_name(krate.crate_id) {
|
||||
Some(name) => builder.field(&name),
|
||||
None => builder.field(&krate.crate_id),
|
||||
}
|
||||
.finish()
|
||||
}
|
||||
|
||||
fn debug_module(&self, module: Module, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let file_id = module.definition_source(self).file_id.original_file(self);
|
||||
let path = self.file_path(file_id);
|
||||
fmt.debug_struct("Module")
|
||||
.field("name", &module.name(self).unwrap_or_else(Name::missing))
|
||||
.field("path", &path.unwrap_or_else(|| "N/A".to_string()))
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
fn debug_fn(f: impl FnOnce(&mut fmt::Formatter<'_>) -> fmt::Result) -> impl fmt::Debug {
|
||||
struct DebugFn<F>(Cell<Option<F>>);
|
||||
|
||||
impl<F: FnOnce(&mut fmt::Formatter<'_>) -> fmt::Result> fmt::Debug for DebugFn<F> {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let f = self.0.take().unwrap();
|
||||
f(fmt)
|
||||
}
|
||||
}
|
||||
|
||||
DebugFn(Cell::new(Some(f)))
|
||||
}
|
|
@ -20,6 +20,7 @@ macro_rules! impl_froms {
|
|||
}
|
||||
|
||||
mod either;
|
||||
pub mod debug;
|
||||
|
||||
pub mod db;
|
||||
#[macro_use]
|
||||
|
|
|
@ -2,13 +2,14 @@ use std::{panic, sync::Arc};
|
|||
|
||||
use parking_lot::Mutex;
|
||||
use ra_db::{
|
||||
salsa, CrateGraph, Edition, FileId, FilePosition, SourceDatabase, SourceRoot, SourceRootId,
|
||||
salsa, CrateGraph, CrateId, Edition, FileId, FilePosition, SourceDatabase, SourceRoot,
|
||||
SourceRootId,
|
||||
};
|
||||
use relative_path::RelativePathBuf;
|
||||
use rustc_hash::FxHashMap;
|
||||
use test_utils::{extract_offset, parse_fixture, CURSOR_MARKER};
|
||||
|
||||
use crate::{db, diagnostics::DiagnosticSink};
|
||||
use crate::{db, debug::HirDebugHelper, diagnostics::DiagnosticSink};
|
||||
|
||||
pub const WORKSPACE: SourceRootId = SourceRootId(0);
|
||||
|
||||
|
@ -24,10 +25,22 @@ pub struct MockDatabase {
|
|||
events: Mutex<Option<Vec<salsa::Event<MockDatabase>>>>,
|
||||
runtime: salsa::Runtime<MockDatabase>,
|
||||
files: FxHashMap<String, FileId>,
|
||||
crate_names: Arc<FxHashMap<CrateId, String>>,
|
||||
file_paths: Arc<FxHashMap<FileId, String>>,
|
||||
}
|
||||
|
||||
impl panic::RefUnwindSafe for MockDatabase {}
|
||||
|
||||
impl HirDebugHelper for MockDatabase {
|
||||
fn crate_name(&self, krate: CrateId) -> Option<String> {
|
||||
self.crate_names.get(&krate).cloned()
|
||||
}
|
||||
|
||||
fn file_path(&self, file_id: FileId) -> Option<String> {
|
||||
self.file_paths.get(&file_id).cloned()
|
||||
}
|
||||
}
|
||||
|
||||
impl MockDatabase {
|
||||
pub fn with_files(fixture: &str) -> MockDatabase {
|
||||
let (db, position) = MockDatabase::from_fixture(fixture);
|
||||
|
@ -62,6 +75,7 @@ impl MockDatabase {
|
|||
for (crate_name, (crate_root, edition, _)) in graph.0.iter() {
|
||||
let crate_root = self.file_id_of(&crate_root);
|
||||
let crate_id = crate_graph.add_crate_root(crate_root, *edition);
|
||||
Arc::make_mut(&mut self.crate_names).insert(crate_id, crate_name.clone());
|
||||
ids.insert(crate_name, crate_id);
|
||||
}
|
||||
for (crate_name, (_, _, deps)) in graph.0.iter() {
|
||||
|
@ -151,8 +165,11 @@ impl MockDatabase {
|
|||
let is_crate_root = rel_path == "lib.rs" || rel_path == "/main.rs";
|
||||
|
||||
let file_id = FileId(self.files.len() as u32);
|
||||
|
||||
let prev = self.files.insert(path.to_string(), file_id);
|
||||
assert!(prev.is_none(), "duplicate files in the text fixture");
|
||||
Arc::make_mut(&mut self.file_paths).insert(file_id, path.to_string());
|
||||
|
||||
let text = Arc::new(text.to_string());
|
||||
self.set_file_text(file_id, text);
|
||||
self.set_file_relative_path(file_id, rel_path.clone());
|
||||
|
@ -200,6 +217,8 @@ impl Default for MockDatabase {
|
|||
events: Default::default(),
|
||||
runtime: salsa::Runtime::default(),
|
||||
files: FxHashMap::default(),
|
||||
crate_names: Default::default(),
|
||||
file_paths: Default::default(),
|
||||
};
|
||||
db.set_crate_graph(Default::default());
|
||||
db
|
||||
|
@ -213,6 +232,8 @@ impl salsa::ParallelDatabase for MockDatabase {
|
|||
runtime: self.runtime.snapshot(self),
|
||||
// only the root database can be used to get file_id by path.
|
||||
files: FxHashMap::default(),
|
||||
file_paths: Arc::clone(&self.file_paths),
|
||||
crate_names: Arc::clone(&self.crate_names),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ use std::{fmt, sync::Arc, time};
|
|||
|
||||
use ra_db::{
|
||||
salsa::{Database, Durability, SweepStrategy},
|
||||
CrateGraph, FileId, SourceDatabase, SourceRoot, SourceRootId,
|
||||
CrateGraph, CrateId, FileId, SourceDatabase, SourceRoot, SourceRootId,
|
||||
};
|
||||
use ra_prof::{memory_usage, profile, Bytes};
|
||||
use ra_syntax::SourceFile;
|
||||
|
@ -11,7 +11,7 @@ use relative_path::RelativePathBuf;
|
|||
use rustc_hash::FxHashMap;
|
||||
|
||||
use crate::{
|
||||
db::RootDatabase,
|
||||
db::{DebugData, RootDatabase},
|
||||
status::syntax_tree_stats,
|
||||
symbol_index::{SymbolIndex, SymbolsDatabase},
|
||||
};
|
||||
|
@ -23,6 +23,7 @@ pub struct AnalysisChange {
|
|||
files_changed: Vec<(FileId, Arc<String>)>,
|
||||
libraries_added: Vec<LibraryData>,
|
||||
crate_graph: Option<CrateGraph>,
|
||||
debug_data: DebugData,
|
||||
}
|
||||
|
||||
impl fmt::Debug for AnalysisChange {
|
||||
|
@ -83,6 +84,14 @@ impl AnalysisChange {
|
|||
pub fn set_crate_graph(&mut self, graph: CrateGraph) {
|
||||
self.crate_graph = Some(graph);
|
||||
}
|
||||
|
||||
pub fn set_debug_crate_name(&mut self, crate_id: CrateId, name: String) {
|
||||
self.debug_data.crate_names.insert(crate_id, name);
|
||||
}
|
||||
|
||||
pub fn set_debug_root_path(&mut self, source_root_id: SourceRootId, path: String) {
|
||||
self.debug_data.root_paths.insert(source_root_id, path);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
@ -200,6 +209,8 @@ impl RootDatabase {
|
|||
if let Some(crate_graph) = change.crate_graph {
|
||||
self.set_crate_graph_with_durability(Arc::new(crate_graph), Durability::HIGH)
|
||||
}
|
||||
|
||||
Arc::make_mut(&mut self.debug_data).merge(change.debug_data)
|
||||
}
|
||||
|
||||
fn apply_root_change(&mut self, root_id: SourceRootId, root_change: RootChange) {
|
||||
|
|
|
@ -2,8 +2,9 @@ use std::{sync::Arc, time};
|
|||
|
||||
use ra_db::{
|
||||
salsa::{self, Database, Durability},
|
||||
Canceled, CheckCanceled, FileId, SourceDatabase,
|
||||
Canceled, CheckCanceled, CrateId, FileId, SourceDatabase, SourceRootId,
|
||||
};
|
||||
use rustc_hash::FxHashMap;
|
||||
|
||||
use crate::{
|
||||
symbol_index::{self, SymbolsDatabase},
|
||||
|
@ -23,10 +24,23 @@ use crate::{
|
|||
pub(crate) struct RootDatabase {
|
||||
runtime: salsa::Runtime<RootDatabase>,
|
||||
pub(crate) feature_flags: Arc<FeatureFlags>,
|
||||
pub(crate) debug_data: Arc<DebugData>,
|
||||
pub(crate) last_gc: time::Instant,
|
||||
pub(crate) last_gc_check: time::Instant,
|
||||
}
|
||||
|
||||
impl hir::debug::HirDebugHelper for RootDatabase {
|
||||
fn crate_name(&self, krate: CrateId) -> Option<String> {
|
||||
self.debug_data.crate_names.get(&krate).cloned()
|
||||
}
|
||||
fn file_path(&self, file_id: FileId) -> Option<String> {
|
||||
let source_root_id = self.file_source_root(file_id);
|
||||
let source_root_path = self.debug_data.root_paths.get(&source_root_id)?;
|
||||
let file_path = self.file_relative_path(file_id);
|
||||
Some(format!("{}/{}", source_root_path, file_path.display()))
|
||||
}
|
||||
}
|
||||
|
||||
impl salsa::Database for RootDatabase {
|
||||
fn salsa_runtime(&self) -> &salsa::Runtime<RootDatabase> {
|
||||
&self.runtime
|
||||
|
@ -58,6 +72,7 @@ impl RootDatabase {
|
|||
last_gc: time::Instant::now(),
|
||||
last_gc_check: time::Instant::now(),
|
||||
feature_flags: Arc::new(feature_flags),
|
||||
debug_data: Default::default(),
|
||||
};
|
||||
db.set_crate_graph_with_durability(Default::default(), Durability::HIGH);
|
||||
db.set_local_roots_with_durability(Default::default(), Durability::HIGH);
|
||||
|
@ -77,6 +92,7 @@ impl salsa::ParallelDatabase for RootDatabase {
|
|||
last_gc: self.last_gc,
|
||||
last_gc_check: self.last_gc_check,
|
||||
feature_flags: Arc::clone(&self.feature_flags),
|
||||
debug_data: Arc::clone(&self.debug_data),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -90,3 +106,16 @@ fn line_index(db: &impl ra_db::SourceDatabase, file_id: FileId) -> Arc<LineIndex
|
|||
let text = db.file_text(file_id);
|
||||
Arc::new(LineIndex::new(&*text))
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Clone)]
|
||||
pub(crate) struct DebugData {
|
||||
pub(crate) root_paths: FxHashMap<SourceRootId, String>,
|
||||
pub(crate) crate_names: FxHashMap<CrateId, String>,
|
||||
}
|
||||
|
||||
impl DebugData {
|
||||
pub(crate) fn merge(&mut self, other: DebugData) {
|
||||
self.root_paths.extend(other.root_paths.into_iter());
|
||||
self.crate_names.extend(other.crate_names.into_iter());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@ parking_lot = "0.9.0"
|
|||
jod-thread = "0.1.0"
|
||||
ra_vfs = "0.4.0"
|
||||
ra_syntax = { path = "../ra_syntax" }
|
||||
ra_db = { path = "../ra_db" }
|
||||
ra_text_edit = { path = "../ra_text_edit" }
|
||||
ra_ide_api = { path = "../ra_ide_api" }
|
||||
lsp-server = "0.2.0"
|
||||
|
|
|
@ -92,6 +92,7 @@ impl WorldState {
|
|||
let vfs_root_path = vfs.root2path(r);
|
||||
let is_local = folder_roots.iter().any(|it| vfs_root_path.starts_with(it));
|
||||
change.add_root(SourceRootId(r.0), is_local);
|
||||
change.set_debug_root_path(SourceRootId(r.0), vfs_root_path.display().to_string());
|
||||
}
|
||||
|
||||
// Create crate graph from all the workspaces
|
||||
|
@ -101,7 +102,11 @@ impl WorldState {
|
|||
vfs_file.map(|f| FileId(f.0))
|
||||
};
|
||||
for ws in workspaces.iter() {
|
||||
crate_graph.extend(ws.to_crate_graph(&mut load));
|
||||
let (graph, crate_names) = ws.to_crate_graph(&mut load);
|
||||
let shift = crate_graph.extend(graph);
|
||||
for (crate_id, name) in crate_names {
|
||||
change.set_debug_crate_name(crate_id.shift(shift), name)
|
||||
}
|
||||
}
|
||||
change.set_crate_graph(crate_graph);
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@ use std::{
|
|||
path::{Path, PathBuf},
|
||||
};
|
||||
|
||||
use ra_db::{CrateGraph, Edition, FileId};
|
||||
use ra_db::{CrateGraph, CrateId, Edition, FileId};
|
||||
use rustc_hash::FxHashMap;
|
||||
use serde_json::from_reader;
|
||||
|
||||
|
@ -113,8 +113,12 @@ impl ProjectWorkspace {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn to_crate_graph(&self, load: &mut dyn FnMut(&Path) -> Option<FileId>) -> CrateGraph {
|
||||
pub fn to_crate_graph(
|
||||
&self,
|
||||
load: &mut dyn FnMut(&Path) -> Option<FileId>,
|
||||
) -> (CrateGraph, FxHashMap<CrateId, String>) {
|
||||
let mut crate_graph = CrateGraph::default();
|
||||
let mut names = FxHashMap::default();
|
||||
match self {
|
||||
ProjectWorkspace::Json { project } => {
|
||||
let mut crates = FxHashMap::default();
|
||||
|
@ -151,10 +155,9 @@ impl ProjectWorkspace {
|
|||
let mut sysroot_crates = FxHashMap::default();
|
||||
for krate in sysroot.crates() {
|
||||
if let Some(file_id) = load(krate.root(&sysroot)) {
|
||||
sysroot_crates.insert(
|
||||
krate,
|
||||
crate_graph.add_crate_root(file_id, Edition::Edition2018),
|
||||
);
|
||||
let crate_id = crate_graph.add_crate_root(file_id, Edition::Edition2018);
|
||||
sysroot_crates.insert(krate, crate_id);
|
||||
names.insert(crate_id, krate.name(&sysroot).to_string());
|
||||
}
|
||||
}
|
||||
for from in sysroot.crates() {
|
||||
|
@ -182,6 +185,7 @@ impl ProjectWorkspace {
|
|||
if let Some(file_id) = load(root) {
|
||||
let edition = pkg.edition(&cargo);
|
||||
let crate_id = crate_graph.add_crate_root(file_id, edition);
|
||||
names.insert(crate_id, pkg.name(&cargo).to_string());
|
||||
if tgt.kind(&cargo) == TargetKind::Lib {
|
||||
lib_tgt = Some(crate_id);
|
||||
pkg_to_lib_crate.insert(pkg, crate_id);
|
||||
|
@ -212,7 +216,7 @@ impl ProjectWorkspace {
|
|||
}
|
||||
}
|
||||
|
||||
// Now add a dep ednge from all targets of upstream to the lib
|
||||
// Now add a dep edge from all targets of upstream to the lib
|
||||
// target of downstream.
|
||||
for pkg in cargo.packages() {
|
||||
for dep in pkg.dependencies(&cargo) {
|
||||
|
@ -233,7 +237,7 @@ impl ProjectWorkspace {
|
|||
}
|
||||
}
|
||||
}
|
||||
crate_graph
|
||||
(crate_graph, names)
|
||||
}
|
||||
|
||||
pub fn workspace_root_for(&self, path: &Path) -> Option<&Path> {
|
||||
|
|
Loading…
Reference in a new issue