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

1
Cargo.lock generated
View file

@ -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",

View file

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

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

View file

@ -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) {

View file

@ -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());
}
}

View file

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

View file

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

View file

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