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:
Aleksey Kladov 2019-09-08 09:48:45 +03:00
parent 734a43e95a
commit ef2b84ddf1
11 changed files with 166 additions and 18 deletions

View file

@ -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>;

View 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)))
}

View file

@ -20,6 +20,7 @@ macro_rules! impl_froms {
}
mod either;
pub mod debug;
pub mod db;
#[macro_use]

View file

@ -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),
})
}
}