mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-11-16 09:48:10 +00:00
Don't keep the parent DefMap alive via Arc
This seems like it could easily leak a lot of memory since we don't currently run GC
This commit is contained in:
parent
01bc1fdff8
commit
26a2a2433c
5 changed files with 67 additions and 36 deletions
|
@ -34,7 +34,7 @@ fn check_diagnostics(ra_fixture: &str) {
|
||||||
db.check_diagnostics();
|
db.check_diagnostics();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn block_def_map_at(ra_fixture: &str) -> Arc<DefMap> {
|
fn block_def_map_at(ra_fixture: &str) -> String {
|
||||||
let (db, position) = crate::test_db::TestDB::with_position(ra_fixture);
|
let (db, position) = crate::test_db::TestDB::with_position(ra_fixture);
|
||||||
|
|
||||||
let krate = db.crate_graph().iter().next().unwrap();
|
let krate = db.crate_graph().iter().next().unwrap();
|
||||||
|
@ -51,7 +51,7 @@ fn block_def_map_at(ra_fixture: &str) -> Arc<DefMap> {
|
||||||
block = new_block;
|
block = new_block;
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
return def_map;
|
return def_map.dump(&db);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -138,8 +138,7 @@ fn block_at_pos(db: &dyn DefDatabase, def_map: &DefMap, position: FilePosition)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_at(ra_fixture: &str, expect: Expect) {
|
fn check_at(ra_fixture: &str, expect: Expect) {
|
||||||
let def_map = block_def_map_at(ra_fixture);
|
let actual = block_def_map_at(ra_fixture);
|
||||||
let actual = def_map.dump();
|
|
||||||
expect.assert_eq(&actual);
|
expect.assert_eq(&actual);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -100,11 +100,12 @@ pub struct DefMap {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// For `DefMap`s computed for a block expression, this stores its location in the parent map.
|
/// For `DefMap`s computed for a block expression, this stores its location in the parent map.
|
||||||
#[derive(Debug, PartialEq, Eq)]
|
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
||||||
struct BlockInfo {
|
struct BlockInfo {
|
||||||
|
/// The `BlockId` this `DefMap` was created from.
|
||||||
block: BlockId,
|
block: BlockId,
|
||||||
parent: Arc<DefMap>,
|
/// The containing module.
|
||||||
parent_module: LocalModuleId,
|
parent: ModuleId,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::ops::Index<LocalModuleId> for DefMap {
|
impl std::ops::Index<LocalModuleId> for DefMap {
|
||||||
|
@ -211,17 +212,16 @@ impl DefMap {
|
||||||
block_id: BlockId,
|
block_id: BlockId,
|
||||||
) -> Option<Arc<DefMap>> {
|
) -> Option<Arc<DefMap>> {
|
||||||
let block: BlockLoc = db.lookup_intern_block(block_id);
|
let block: BlockLoc = db.lookup_intern_block(block_id);
|
||||||
let parent = block.module.def_map(db);
|
|
||||||
|
|
||||||
let item_tree = db.item_tree(block.ast_id.file_id);
|
let item_tree = db.item_tree(block.ast_id.file_id);
|
||||||
if item_tree.inner_items_of_block(block.ast_id.value).is_empty() {
|
if item_tree.inner_items_of_block(block.ast_id.value).is_empty() {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
let block_info =
|
let block_info = BlockInfo { block: block_id, parent: block.module };
|
||||||
BlockInfo { block: block_id, parent, parent_module: block.module.local_id };
|
|
||||||
|
|
||||||
let mut def_map = DefMap::empty(block.module.krate, block_info.parent.edition);
|
let parent_map = block.module.def_map(db);
|
||||||
|
let mut def_map = DefMap::empty(block.module.krate, parent_map.edition);
|
||||||
def_map.block = Some(block_info);
|
def_map.block = Some(block_info);
|
||||||
|
|
||||||
let def_map = collector::collect_defs(db, def_map, Some(block.ast_id));
|
let def_map = collector::collect_defs(db, def_map, Some(block.ast_id));
|
||||||
|
@ -289,9 +289,15 @@ impl DefMap {
|
||||||
ModuleId { krate: self.krate, local_id, block }
|
ModuleId { krate: self.krate, local_id, block }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn crate_root(&self) -> ModuleId {
|
pub(crate) fn crate_root(&self, db: &dyn DefDatabase) -> ModuleId {
|
||||||
let (root_map, _) = self.ancestor_maps(self.root).last().unwrap();
|
self.with_ancestor_maps(db, self.root, &mut |def_map, _module| {
|
||||||
root_map.module_id(root_map.root)
|
if def_map.block.is_none() {
|
||||||
|
Some(def_map.module_id(def_map.root))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.expect("DefMap chain without root")
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn resolve_path(
|
pub(crate) fn resolve_path(
|
||||||
|
@ -306,26 +312,42 @@ impl DefMap {
|
||||||
(res.resolved_def, res.segment_index)
|
(res.resolved_def, res.segment_index)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Iterates over the containing `DefMap`s, if `self` is a `DefMap` corresponding to a block
|
/// Ascends the `DefMap` hierarchy and calls `f` with every `DefMap` and containing module.
|
||||||
/// expression.
|
///
|
||||||
fn ancestor_maps(
|
/// If `f` returns `Some(val)`, iteration is stopped and `Some(val)` is returned. If `f` returns
|
||||||
|
/// `None`, iteration continues.
|
||||||
|
fn with_ancestor_maps<T>(
|
||||||
&self,
|
&self,
|
||||||
|
db: &dyn DefDatabase,
|
||||||
local_mod: LocalModuleId,
|
local_mod: LocalModuleId,
|
||||||
) -> impl Iterator<Item = (&DefMap, LocalModuleId)> {
|
f: &mut dyn FnMut(&DefMap, LocalModuleId) -> Option<T>,
|
||||||
std::iter::successors(Some((self, local_mod)), |(map, _)| {
|
) -> Option<T> {
|
||||||
map.block.as_ref().map(|block| (&*block.parent, block.parent_module))
|
if let Some(it) = f(self, local_mod) {
|
||||||
})
|
return Some(it);
|
||||||
|
}
|
||||||
|
let mut block = self.block;
|
||||||
|
while let Some(block_info) = block {
|
||||||
|
let parent = block_info.parent.def_map(db);
|
||||||
|
if let Some(it) = f(&parent, block_info.parent.local_id) {
|
||||||
|
return Some(it);
|
||||||
|
}
|
||||||
|
block = parent.block;
|
||||||
|
}
|
||||||
|
|
||||||
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: this can use some more human-readable format (ideally, an IR
|
// FIXME: this can use some more human-readable format (ideally, an IR
|
||||||
// even), as this should be a great debugging aid.
|
// even), as this should be a great debugging aid.
|
||||||
pub fn dump(&self) -> String {
|
pub fn dump(&self, db: &dyn DefDatabase) -> String {
|
||||||
let mut buf = String::new();
|
let mut buf = String::new();
|
||||||
|
let mut arc;
|
||||||
let mut current_map = self;
|
let mut current_map = self;
|
||||||
while let Some(block) = ¤t_map.block {
|
while let Some(block) = ¤t_map.block {
|
||||||
go(&mut buf, current_map, "block scope", current_map.root);
|
go(&mut buf, current_map, "block scope", current_map.root);
|
||||||
buf.push('\n');
|
buf.push('\n');
|
||||||
current_map = &*block.parent;
|
arc = block.parent.def_map(db);
|
||||||
|
current_map = &*arc;
|
||||||
}
|
}
|
||||||
go(&mut buf, current_map, "crate", current_map.root);
|
go(&mut buf, current_map, "crate", current_map.root);
|
||||||
return buf;
|
return buf;
|
||||||
|
|
|
@ -1449,10 +1449,11 @@ impl ModCollector<'_, '_> {
|
||||||
if let Some(macro_call_id) =
|
if let Some(macro_call_id) =
|
||||||
ast_id.as_call_id(self.def_collector.db, self.def_collector.def_map.krate, |path| {
|
ast_id.as_call_id(self.def_collector.db, self.def_collector.def_map.krate, |path| {
|
||||||
path.as_ident().and_then(|name| {
|
path.as_ident().and_then(|name| {
|
||||||
self.def_collector
|
self.def_collector.def_map.with_ancestor_maps(
|
||||||
.def_map
|
self.def_collector.db,
|
||||||
.ancestor_maps(self.module_id)
|
self.module_id,
|
||||||
.find_map(|(map, module)| map[module].scope.get_legacy_macro(&name))
|
&mut |map, module| map[module].scope.get_legacy_macro(&name),
|
||||||
|
)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
{
|
{
|
||||||
|
|
|
@ -110,6 +110,7 @@ impl DefMap {
|
||||||
let mut result = ResolvePathResult::empty(ReachedFixedPoint::No);
|
let mut result = ResolvePathResult::empty(ReachedFixedPoint::No);
|
||||||
result.segment_index = Some(usize::max_value());
|
result.segment_index = Some(usize::max_value());
|
||||||
|
|
||||||
|
let mut arc;
|
||||||
let mut current_map = self;
|
let mut current_map = self;
|
||||||
loop {
|
loop {
|
||||||
let new = current_map.resolve_path_fp_with_macro_single(
|
let new = current_map.resolve_path_fp_with_macro_single(
|
||||||
|
@ -131,8 +132,9 @@ impl DefMap {
|
||||||
|
|
||||||
match ¤t_map.block {
|
match ¤t_map.block {
|
||||||
Some(block) => {
|
Some(block) => {
|
||||||
current_map = &block.parent;
|
original_module = block.parent.local_id;
|
||||||
original_module = block.parent_module;
|
arc = block.parent.def_map(db);
|
||||||
|
current_map = &*arc;
|
||||||
}
|
}
|
||||||
None => return result,
|
None => return result,
|
||||||
}
|
}
|
||||||
|
@ -152,7 +154,7 @@ impl DefMap {
|
||||||
PathKind::DollarCrate(krate) => {
|
PathKind::DollarCrate(krate) => {
|
||||||
if krate == self.krate {
|
if krate == self.krate {
|
||||||
mark::hit!(macro_dollar_crate_self);
|
mark::hit!(macro_dollar_crate_self);
|
||||||
PerNs::types(self.crate_root().into(), Visibility::Public)
|
PerNs::types(self.crate_root(db).into(), Visibility::Public)
|
||||||
} else {
|
} else {
|
||||||
let def_map = db.crate_def_map(krate);
|
let def_map = db.crate_def_map(krate);
|
||||||
let module = def_map.module_id(def_map.root);
|
let module = def_map.module_id(def_map.root);
|
||||||
|
@ -160,7 +162,7 @@ impl DefMap {
|
||||||
PerNs::types(module.into(), Visibility::Public)
|
PerNs::types(module.into(), Visibility::Public)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
PathKind::Crate => PerNs::types(self.crate_root().into(), Visibility::Public),
|
PathKind::Crate => PerNs::types(self.crate_root(db).into(), Visibility::Public),
|
||||||
// plain import or absolute path in 2015: crate-relative with
|
// plain import or absolute path in 2015: crate-relative with
|
||||||
// fallback to extern prelude (with the simplification in
|
// fallback to extern prelude (with the simplification in
|
||||||
// rust-lang/rust#57745)
|
// rust-lang/rust#57745)
|
||||||
|
@ -206,10 +208,10 @@ impl DefMap {
|
||||||
segments: path.segments.clone(),
|
segments: path.segments.clone(),
|
||||||
};
|
};
|
||||||
log::debug!("`super` path: {} -> {} in parent map", path, new_path);
|
log::debug!("`super` path: {} -> {} in parent map", path, new_path);
|
||||||
return block.parent.resolve_path_fp_with_macro(
|
return block.parent.def_map(db).resolve_path_fp_with_macro(
|
||||||
db,
|
db,
|
||||||
mode,
|
mode,
|
||||||
block.parent_module,
|
block.parent.local_id,
|
||||||
&new_path,
|
&new_path,
|
||||||
shadow,
|
shadow,
|
||||||
);
|
);
|
||||||
|
|
|
@ -11,7 +11,9 @@ use base_db::{fixture::WithFixture, SourceDatabase};
|
||||||
use expect_test::{expect, Expect};
|
use expect_test::{expect, Expect};
|
||||||
use test_utils::mark;
|
use test_utils::mark;
|
||||||
|
|
||||||
use crate::{db::DefDatabase, nameres::*, test_db::TestDB};
|
use crate::{db::DefDatabase, test_db::TestDB};
|
||||||
|
|
||||||
|
use super::DefMap;
|
||||||
|
|
||||||
fn compute_crate_def_map(ra_fixture: &str) -> Arc<DefMap> {
|
fn compute_crate_def_map(ra_fixture: &str) -> Arc<DefMap> {
|
||||||
let db = TestDB::with_files(ra_fixture);
|
let db = TestDB::with_files(ra_fixture);
|
||||||
|
@ -19,9 +21,14 @@ fn compute_crate_def_map(ra_fixture: &str) -> Arc<DefMap> {
|
||||||
db.crate_def_map(krate)
|
db.crate_def_map(krate)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn render_crate_def_map(ra_fixture: &str) -> String {
|
||||||
|
let db = TestDB::with_files(ra_fixture);
|
||||||
|
let krate = db.crate_graph().iter().next().unwrap();
|
||||||
|
db.crate_def_map(krate).dump(&db)
|
||||||
|
}
|
||||||
|
|
||||||
fn check(ra_fixture: &str, expect: Expect) {
|
fn check(ra_fixture: &str, expect: Expect) {
|
||||||
let def_map = compute_crate_def_map(ra_fixture);
|
let actual = render_crate_def_map(ra_fixture);
|
||||||
let actual = def_map.dump();
|
|
||||||
expect.assert_eq(&actual);
|
expect.assert_eq(&actual);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue