6123: Reduce duplication in fixtures r=matklad a=matklad

bors r+
🤖

Co-authored-by: Aleksey Kladov <aleksey.kladov@gmail.com>
This commit is contained in:
bors[bot] 2020-10-02 15:50:20 +00:00 committed by GitHub
commit 673e1ddb9a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
38 changed files with 564 additions and 669 deletions

View file

@ -0,0 +1,97 @@
//! Defines a unit of change that can applied to the database to get the next
//! state. Changes are transactional.
use std::{fmt, sync::Arc};
use rustc_hash::FxHashSet;
use salsa::Durability;
use vfs::FileId;
use crate::{CrateGraph, SourceDatabaseExt, SourceRoot, SourceRootId};
/// Encapsulate a bunch of raw `.set` calls on the database.
#[derive(Default)]
pub struct Change {
pub roots: Option<Vec<SourceRoot>>,
pub files_changed: Vec<(FileId, Option<Arc<String>>)>,
pub crate_graph: Option<CrateGraph>,
}
impl fmt::Debug for Change {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
let mut d = fmt.debug_struct("AnalysisChange");
if let Some(roots) = &self.roots {
d.field("roots", roots);
}
if !self.files_changed.is_empty() {
d.field("files_changed", &self.files_changed.len());
}
if self.crate_graph.is_some() {
d.field("crate_graph", &self.crate_graph);
}
d.finish()
}
}
impl Change {
pub fn new() -> Change {
Change::default()
}
pub fn set_roots(&mut self, roots: Vec<SourceRoot>) {
self.roots = Some(roots);
}
pub fn change_file(&mut self, file_id: FileId, new_text: Option<Arc<String>>) {
self.files_changed.push((file_id, new_text))
}
pub fn set_crate_graph(&mut self, graph: CrateGraph) {
self.crate_graph = Some(graph);
}
pub fn apply(self, db: &mut dyn SourceDatabaseExt) {
let _p = profile::span("RootDatabase::apply_change");
// db.request_cancellation();
// log::info!("apply_change {:?}", change);
if let Some(roots) = self.roots {
let mut local_roots = FxHashSet::default();
let mut library_roots = FxHashSet::default();
for (idx, root) in roots.into_iter().enumerate() {
let root_id = SourceRootId(idx as u32);
let durability = durability(&root);
if root.is_library {
library_roots.insert(root_id);
} else {
local_roots.insert(root_id);
}
for file_id in root.iter() {
db.set_file_source_root_with_durability(file_id, root_id, durability);
}
db.set_source_root_with_durability(root_id, Arc::new(root), durability);
}
// db.set_local_roots_with_durability(Arc::new(local_roots), Durability::HIGH);
// db.set_library_roots_with_durability(Arc::new(library_roots), Durability::HIGH);
}
for (file_id, text) in self.files_changed {
let source_root_id = db.file_source_root(file_id);
let source_root = db.source_root(source_root_id);
let durability = durability(&source_root);
// XXX: can't actually remove the file, just reset the text
let text = text.unwrap_or_default();
db.set_file_text_with_durability(file_id, text, durability)
}
if let Some(crate_graph) = self.crate_graph {
db.set_crate_graph_with_durability(Arc::new(crate_graph), Durability::HIGH)
}
}
}
fn durability(source_root: &SourceRoot) -> Durability {
if source_root.is_library {
Durability::HIGH
} else {
Durability::LOW
}
}

View file

@ -65,24 +65,26 @@ use test_utils::{extract_range_or_offset, Fixture, RangeOrOffset, CURSOR_MARKER}
use vfs::{file_set::FileSet, VfsPath};
use crate::{
input::CrateName, CrateGraph, CrateId, Edition, Env, FileId, FilePosition, SourceDatabaseExt,
SourceRoot, SourceRootId,
input::CrateName, Change, CrateGraph, CrateId, Edition, Env, FileId, FilePosition,
SourceDatabaseExt, SourceRoot, SourceRootId,
};
pub const WORKSPACE: SourceRootId = SourceRootId(0);
pub trait WithFixture: Default + SourceDatabaseExt + 'static {
fn with_single_file(text: &str) -> (Self, FileId) {
let fixture = ChangeFixture::parse(text);
let mut db = Self::default();
let (_, files) = with_files(&mut db, text);
assert_eq!(files.len(), 1);
(db, files[0])
fixture.change.apply(&mut db);
assert_eq!(fixture.files.len(), 1);
(db, fixture.files[0])
}
fn with_files(ra_fixture: &str) -> Self {
let fixture = ChangeFixture::parse(ra_fixture);
let mut db = Self::default();
let (pos, _) = with_files(&mut db, ra_fixture);
assert!(pos.is_none());
fixture.change.apply(&mut db);
assert!(fixture.file_position.is_none());
db
}
@ -96,9 +98,10 @@ pub trait WithFixture: Default + SourceDatabaseExt + 'static {
}
fn with_range_or_offset(ra_fixture: &str) -> (Self, FileId, RangeOrOffset) {
let fixture = ChangeFixture::parse(ra_fixture);
let mut db = Self::default();
let (pos, _) = with_files(&mut db, ra_fixture);
let (file_id, range_or_offset) = pos.unwrap();
fixture.change.apply(&mut db);
let (file_id, range_or_offset) = fixture.file_position.unwrap();
(db, file_id, range_or_offset)
}
@ -113,89 +116,95 @@ pub trait WithFixture: Default + SourceDatabaseExt + 'static {
impl<DB: SourceDatabaseExt + Default + 'static> WithFixture for DB {}
fn with_files(
db: &mut dyn SourceDatabaseExt,
fixture: &str,
) -> (Option<(FileId, RangeOrOffset)>, Vec<FileId>) {
let fixture = Fixture::parse(fixture);
pub struct ChangeFixture {
pub file_position: Option<(FileId, RangeOrOffset)>,
pub files: Vec<FileId>,
pub change: Change,
}
let mut files = Vec::new();
let mut crate_graph = CrateGraph::default();
let mut crates = FxHashMap::default();
let mut crate_deps = Vec::new();
let mut default_crate_root: Option<FileId> = None;
impl ChangeFixture {
pub fn parse(ra_fixture: &str) -> ChangeFixture {
let fixture = Fixture::parse(ra_fixture);
let mut change = Change::new();
let mut file_set = FileSet::default();
let source_root_id = WORKSPACE;
let source_root_prefix = "/".to_string();
let mut file_id = FileId(0);
let mut files = Vec::new();
let mut crate_graph = CrateGraph::default();
let mut crates = FxHashMap::default();
let mut crate_deps = Vec::new();
let mut default_crate_root: Option<FileId> = None;
let mut default_cfg = CfgOptions::default();
let mut file_position = None;
let mut file_set = FileSet::default();
let source_root_prefix = "/".to_string();
let mut file_id = FileId(0);
for entry in fixture {
let text = if entry.text.contains(CURSOR_MARKER) {
let (range_or_offset, text) = extract_range_or_offset(&entry.text);
assert!(file_position.is_none());
file_position = Some((file_id, range_or_offset));
text.to_string()
} else {
entry.text.clone()
};
let mut file_position = None;
let meta = FileMeta::from(entry);
assert!(meta.path.starts_with(&source_root_prefix));
for entry in fixture {
let text = if entry.text.contains(CURSOR_MARKER) {
let (range_or_offset, text) = extract_range_or_offset(&entry.text);
assert!(file_position.is_none());
file_position = Some((file_id, range_or_offset));
text.to_string()
} else {
entry.text.clone()
};
if let Some(krate) = meta.krate {
let crate_id = crate_graph.add_crate_root(
file_id,
meta.edition,
Some(krate.clone()),
meta.cfg,
meta.env,
let meta = FileMeta::from(entry);
assert!(meta.path.starts_with(&source_root_prefix));
if let Some(krate) = meta.krate {
let crate_id = crate_graph.add_crate_root(
file_id,
meta.edition,
Some(krate.clone()),
meta.cfg,
meta.env,
Default::default(),
);
let crate_name = CrateName::new(&krate).unwrap();
let prev = crates.insert(crate_name.clone(), crate_id);
assert!(prev.is_none());
for dep in meta.deps {
let dep = CrateName::new(&dep).unwrap();
crate_deps.push((crate_name.clone(), dep))
}
} else if meta.path == "/main.rs" || meta.path == "/lib.rs" {
assert!(default_crate_root.is_none());
default_crate_root = Some(file_id);
default_cfg = meta.cfg;
}
change.change_file(file_id, Some(Arc::new(text)));
let path = VfsPath::new_virtual_path(meta.path);
file_set.insert(file_id, path.into());
files.push(file_id);
file_id.0 += 1;
}
if crates.is_empty() {
let crate_root = default_crate_root.unwrap();
crate_graph.add_crate_root(
crate_root,
Edition::Edition2018,
Some("test".to_string()),
default_cfg,
Env::default(),
Default::default(),
);
let crate_name = CrateName::new(&krate).unwrap();
let prev = crates.insert(crate_name.clone(), crate_id);
assert!(prev.is_none());
for dep in meta.deps {
let dep = CrateName::new(&dep).unwrap();
crate_deps.push((crate_name.clone(), dep))
} else {
for (from, to) in crate_deps {
let from_id = crates[&from];
let to_id = crates[&to];
crate_graph.add_dep(from_id, CrateName::new(&to).unwrap(), to_id).unwrap();
}
} else if meta.path == "/main.rs" || meta.path == "/lib.rs" {
assert!(default_crate_root.is_none());
default_crate_root = Some(file_id);
}
db.set_file_text(file_id, Arc::new(text));
db.set_file_source_root(file_id, source_root_id);
let path = VfsPath::new_virtual_path(meta.path);
file_set.insert(file_id, path.into());
files.push(file_id);
file_id.0 += 1;
change.set_roots(vec![SourceRoot::new_local(file_set)]);
change.set_crate_graph(crate_graph);
ChangeFixture { file_position, files, change }
}
if crates.is_empty() {
let crate_root = default_crate_root.unwrap();
crate_graph.add_crate_root(
crate_root,
Edition::Edition2018,
None,
CfgOptions::default(),
Env::default(),
Default::default(),
);
} else {
for (from, to) in crate_deps {
let from_id = crates[&from];
let to_id = crates[&to];
crate_graph.add_dep(from_id, CrateName::new(&to).unwrap(), to_id).unwrap();
}
}
db.set_source_root(source_root_id, Arc::new(SourceRoot::new_local(file_set)));
db.set_crate_graph(Arc::new(crate_graph));
(file_position, files)
}
struct FileMeta {

View file

@ -1,6 +1,7 @@
//! base_db defines basic database traits. The concrete DB is defined by ide.
mod cancellation;
mod input;
mod change;
pub mod fixture;
use std::{panic, sync::Arc};
@ -10,6 +11,7 @@ use syntax::{ast, Parse, SourceFile, TextRange, TextSize};
pub use crate::{
cancellation::Canceled,
change::Change,
input::{
CrateData, CrateGraph, CrateId, CrateName, Dependency, Edition, Env, FileId, ProcMacroId,
SourceRoot, SourceRootId,

View file

@ -139,7 +139,7 @@ impl CallLocations {
mod tests {
use base_db::FilePosition;
use crate::mock_analysis::analysis_and_position;
use crate::fixture;
fn check_hierarchy(
ra_fixture: &str,
@ -147,7 +147,7 @@ mod tests {
expected_incoming: &[&str],
expected_outgoing: &[&str],
) {
let (analysis, pos) = analysis_and_position(ra_fixture);
let (analysis, pos) = fixture::position(ra_fixture);
let mut navs = analysis.call_hierarchy(pos).unwrap().unwrap().info;
assert_eq!(navs.len(), 1);
@ -181,8 +181,8 @@ fn caller() {
call<|>ee();
}
"#,
"callee FN FileId(1) 0..14 3..9",
&["caller FN FileId(1) 15..44 18..24 : [33..39]"],
"callee FN FileId(0) 0..14 3..9",
&["caller FN FileId(0) 15..44 18..24 : [33..39]"],
&[],
);
}
@ -197,8 +197,8 @@ fn caller() {
callee();
}
"#,
"callee FN FileId(1) 0..14 3..9",
&["caller FN FileId(1) 15..44 18..24 : [33..39]"],
"callee FN FileId(0) 0..14 3..9",
&["caller FN FileId(0) 15..44 18..24 : [33..39]"],
&[],
);
}
@ -214,8 +214,8 @@ fn caller() {
callee();
}
"#,
"callee FN FileId(1) 0..14 3..9",
&["caller FN FileId(1) 15..58 18..24 : [33..39, 47..53]"],
"callee FN FileId(0) 0..14 3..9",
&["caller FN FileId(0) 15..58 18..24 : [33..39, 47..53]"],
&[],
);
}
@ -234,10 +234,10 @@ fn caller2() {
callee();
}
"#,
"callee FN FileId(1) 0..14 3..9",
"callee FN FileId(0) 0..14 3..9",
&[
"caller1 FN FileId(1) 15..45 18..25 : [34..40]",
"caller2 FN FileId(1) 47..77 50..57 : [66..72]",
"caller1 FN FileId(0) 15..45 18..25 : [34..40]",
"caller2 FN FileId(0) 47..77 50..57 : [66..72]",
],
&[],
);
@ -263,10 +263,10 @@ mod tests {
}
}
"#,
"callee FN FileId(1) 0..14 3..9",
"callee FN FileId(0) 0..14 3..9",
&[
"caller1 FN FileId(1) 15..45 18..25 : [34..40]",
"test_caller FN FileId(1) 95..149 110..121 : [134..140]",
"caller1 FN FileId(0) 15..45 18..25 : [34..40]",
"test_caller FN FileId(0) 95..149 110..121 : [134..140]",
],
&[],
);
@ -287,8 +287,8 @@ fn caller() {
//- /foo/mod.rs
pub fn callee() {}
"#,
"callee FN FileId(2) 0..18 7..13",
&["caller FN FileId(1) 27..56 30..36 : [45..51]"],
"callee FN FileId(1) 0..18 7..13",
&["caller FN FileId(0) 27..56 30..36 : [45..51]"],
&[],
);
}
@ -304,9 +304,9 @@ fn call<|>er() {
callee();
}
"#,
"caller FN FileId(1) 15..58 18..24",
"caller FN FileId(0) 15..58 18..24",
&[],
&["callee FN FileId(1) 0..14 3..9 : [33..39, 47..53]"],
&["callee FN FileId(0) 0..14 3..9 : [33..39, 47..53]"],
);
}
@ -325,9 +325,9 @@ fn call<|>er() {
//- /foo/mod.rs
pub fn callee() {}
"#,
"caller FN FileId(1) 27..56 30..36",
"caller FN FileId(0) 27..56 30..36",
&[],
&["callee FN FileId(2) 0..18 7..13 : [45..51]"],
&["callee FN FileId(1) 0..18 7..13 : [45..51]"],
);
}
@ -348,9 +348,9 @@ fn caller3() {
}
"#,
"caller2 FN FileId(1) 33..64 36..43",
&["caller1 FN FileId(1) 0..31 3..10 : [19..26]"],
&["caller3 FN FileId(1) 66..83 69..76 : [52..59]"],
"caller2 FN FileId(0) 33..64 36..43",
&["caller1 FN FileId(0) 0..31 3..10 : [19..26]"],
&["caller3 FN FileId(0) 66..83 69..76 : [52..59]"],
);
}
@ -368,9 +368,9 @@ fn main() {
a<|>()
}
"#,
"a FN FileId(1) 0..18 3..4",
&["main FN FileId(1) 31..52 34..38 : [47..48]"],
&["b FN FileId(1) 20..29 23..24 : [13..14]"],
"a FN FileId(0) 0..18 3..4",
&["main FN FileId(0) 31..52 34..38 : [47..48]"],
&["b FN FileId(0) 20..29 23..24 : [13..14]"],
);
check_hierarchy(
@ -385,8 +385,8 @@ fn main() {
a()
}
"#,
"b FN FileId(1) 20..29 23..24",
&["a FN FileId(1) 0..18 3..4 : [13..14]"],
"b FN FileId(0) 20..29 23..24",
&["a FN FileId(0) 0..18 3..4 : [13..14]"],
&[],
);
}

View file

@ -232,10 +232,10 @@ mod tests {
use expect_test::{expect, Expect};
use test_utils::mark;
use crate::mock_analysis::analysis_and_position;
use crate::fixture;
fn check(ra_fixture: &str, expect: Expect) {
let (analysis, position) = analysis_and_position(ra_fixture);
let (analysis, position) = fixture::position(ra_fixture);
let call_info = analysis.call_info(position).unwrap();
let actual = match call_info {
Some(call_info) => {

View file

@ -133,7 +133,7 @@ pub(crate) fn completions(
#[cfg(test)]
mod tests {
use crate::completion::completion_config::CompletionConfig;
use crate::mock_analysis::analysis_and_position;
use crate::fixture;
struct DetailAndDocumentation<'a> {
detail: &'a str,
@ -141,7 +141,7 @@ mod tests {
}
fn check_detail_and_documentation(ra_fixture: &str, expected: DetailAndDocumentation) {
let (analysis, position) = analysis_and_position(ra_fixture);
let (analysis, position) = fixture::position(ra_fixture);
let config = CompletionConfig::default();
let completions = analysis.completions(&config, position).unwrap().unwrap();
for item in completions {

View file

@ -495,13 +495,13 @@ Some multi-line comment<|>
fn test_completion_await_impls_future() {
check(
r#"
//- /main.rs
//- /main.rs crate:main deps:std
use std::future::*;
struct A {}
impl Future for A {}
fn foo(a: A) { a.<|> }
//- /std/lib.rs
//- /std/lib.rs crate:std
pub mod future {
#[lang = "future_trait"]
pub trait Future {}
@ -514,14 +514,14 @@ pub mod future {
check(
r#"
//- /main.rs
//- /main.rs crate:main deps:std
use std::future::*;
fn foo() {
let a = async {};
a.<|>
}
//- /std/lib.rs
//- /std/lib.rs crate:std
pub mod future {
#[lang = "future_trait"]
pub trait Future {

View file

@ -300,7 +300,7 @@ mod tests {
// "#,
// expect![[r#"
// md bar;
// "#]],
// "#]],foo
// );
// }
@ -308,7 +308,7 @@ mod tests {
fn already_declared_bin_module_completion_omitted() {
check(
r#"
//- /src/bin.rs
//- /src/bin.rs crate:main
fn main() {}
//- /src/bin/foo.rs
mod <|>

View file

@ -422,10 +422,10 @@ fn foo() { let _ = U::<|> }
fn completes_use_paths_across_crates() {
check(
r#"
//- /main.rs
//- /main.rs crate:main deps:foo
use foo::<|>;
//- /foo/lib.rs
//- /foo/lib.rs crate:foo
pub mod bar { pub struct S; }
"#,
expect![[r#"

View file

@ -271,10 +271,10 @@ fn quux() { <|> }
fn completes_extern_prelude() {
check(
r#"
//- /lib.rs
//- /lib.rs crate:main deps:other_crate
use <|>;
//- /other_crate/lib.rs
//- /other_crate/lib.rs crate:other_crate
// nothing here
"#,
expect![[r#"
@ -350,10 +350,10 @@ fn foo() {
fn completes_prelude() {
check(
r#"
//- /main.rs
//- /main.rs crate:main deps:std
fn foo() { let x: <|> }
//- /std/lib.rs
//- /std/lib.rs crate:std
#[prelude_import]
use prelude::*;
@ -371,16 +371,16 @@ mod prelude { struct Option; }
fn completes_std_prelude_if_core_is_defined() {
check(
r#"
//- /main.rs
//- /main.rs crate:main deps:core,std
fn foo() { let x: <|> }
//- /core/lib.rs
//- /core/lib.rs crate:core
#[prelude_import]
use prelude::*;
mod prelude { struct Option; }
//- /std/lib.rs
//- /std/lib.rs crate:std deps:core
#[prelude_import]
use prelude::*;

View file

@ -1172,9 +1172,9 @@ fn foo(xs: Vec<i128>)
check_edit(
"frobnicate!",
r#"
//- /main.rs
//- /main.rs crate:main deps:foo
use foo::<|>;
//- /foo/lib.rs
//- /foo/lib.rs crate:foo
#[macro_export]
macro_rules frobnicate { () => () }
"#,

View file

@ -8,8 +8,7 @@ use test_utils::assert_eq_text;
use crate::{
completion::{completion_item::CompletionKind, CompletionConfig},
mock_analysis::analysis_and_position,
CompletionItem,
fixture, CompletionItem,
};
pub(crate) fn do_completion(code: &str, kind: CompletionKind) -> Vec<CompletionItem> {
@ -80,7 +79,7 @@ pub(crate) fn check_edit_with_config(
ra_fixture_after: &str,
) {
let ra_fixture_after = trim_indent(ra_fixture_after);
let (analysis, position) = analysis_and_position(ra_fixture_before);
let (analysis, position) = fixture::position(ra_fixture_before);
let completions: Vec<CompletionItem> =
analysis.completions(&config, position).unwrap().unwrap().into();
let (completion,) = completions
@ -94,7 +93,7 @@ pub(crate) fn check_edit_with_config(
}
pub(crate) fn check_pattern_is_applicable(code: &str, check: fn(SyntaxElement) -> bool) {
let (analysis, pos) = analysis_and_position(code);
let (analysis, pos) = fixture::position(code);
analysis
.with_db(|db| {
let sema = Semantics::new(db);
@ -109,6 +108,6 @@ pub(crate) fn get_all_completion_items(
config: CompletionConfig,
code: &str,
) -> Vec<CompletionItem> {
let (analysis, position) = analysis_and_position(code);
let (analysis, position) = fixture::position(code);
analysis.completions(&config, position).unwrap().unwrap().into()
}

View file

@ -218,10 +218,7 @@ mod tests {
use stdx::trim_indent;
use test_utils::assert_eq_text;
use crate::{
mock_analysis::{analysis_and_position, single_file, MockAnalysis},
DiagnosticsConfig,
};
use crate::{fixture, DiagnosticsConfig};
/// Takes a multi-file input fixture with annotated cursor positions,
/// and checks that:
@ -231,7 +228,7 @@ mod tests {
fn check_fix(ra_fixture_before: &str, ra_fixture_after: &str) {
let after = trim_indent(ra_fixture_after);
let (analysis, file_position) = analysis_and_position(ra_fixture_before);
let (analysis, file_position) = fixture::position(ra_fixture_before);
let diagnostic = analysis
.diagnostics(&DiagnosticsConfig::default(), file_position.file_id)
.unwrap()
@ -260,7 +257,7 @@ mod tests {
/// which has a fix that can apply to other files.
fn check_apply_diagnostic_fix_in_other_file(ra_fixture_before: &str, ra_fixture_after: &str) {
let ra_fixture_after = &trim_indent(ra_fixture_after);
let (analysis, file_pos) = analysis_and_position(ra_fixture_before);
let (analysis, file_pos) = fixture::position(ra_fixture_before);
let current_file_id = file_pos.file_id;
let diagnostic = analysis
.diagnostics(&DiagnosticsConfig::default(), current_file_id)
@ -282,9 +279,7 @@ mod tests {
/// Takes a multi-file input fixture with annotated cursor position and checks that no diagnostics
/// apply to the file containing the cursor.
fn check_no_diagnostics(ra_fixture: &str) {
let mock = MockAnalysis::with_files(ra_fixture);
let files = mock.files().map(|(it, _)| it).collect::<Vec<_>>();
let analysis = mock.analysis();
let (analysis, files) = fixture::files(ra_fixture);
let diagnostics = files
.into_iter()
.flat_map(|file_id| {
@ -295,7 +290,7 @@ mod tests {
}
fn check_expect(ra_fixture: &str, expect: Expect) {
let (analysis, file_id) = single_file(ra_fixture);
let (analysis, file_id) = fixture::file(ra_fixture);
let diagnostics = analysis.diagnostics(&DiagnosticsConfig::default(), file_id).unwrap();
expect.assert_debug_eq(&diagnostics)
}
@ -304,7 +299,7 @@ mod tests {
fn test_wrap_return_type() {
check_fix(
r#"
//- /main.rs
//- /main.rs crate:main deps:core
use core::result::Result::{self, Ok, Err};
fn div(x: i32, y: i32) -> Result<i32, ()> {
@ -313,7 +308,7 @@ fn div(x: i32, y: i32) -> Result<i32, ()> {
}
x / y<|>
}
//- /core/lib.rs
//- /core/lib.rs crate:core
pub mod result {
pub enum Result<T, E> { Ok(T), Err(E) }
}
@ -335,7 +330,7 @@ fn div(x: i32, y: i32) -> Result<i32, ()> {
fn test_wrap_return_type_handles_generic_functions() {
check_fix(
r#"
//- /main.rs
//- /main.rs crate:main deps:core
use core::result::Result::{self, Ok, Err};
fn div<T>(x: T) -> Result<T, i32> {
@ -344,7 +339,7 @@ fn div<T>(x: T) -> Result<T, i32> {
}
<|>x
}
//- /core/lib.rs
//- /core/lib.rs crate:core
pub mod result {
pub enum Result<T, E> { Ok(T), Err(E) }
}
@ -366,7 +361,7 @@ fn div<T>(x: T) -> Result<T, i32> {
fn test_wrap_return_type_handles_type_aliases() {
check_fix(
r#"
//- /main.rs
//- /main.rs crate:main deps:core
use core::result::Result::{self, Ok, Err};
type MyResult<T> = Result<T, ()>;
@ -377,7 +372,7 @@ fn div(x: i32, y: i32) -> MyResult<i32> {
}
x <|>/ y
}
//- /core/lib.rs
//- /core/lib.rs crate:core
pub mod result {
pub enum Result<T, E> { Ok(T), Err(E) }
}
@ -401,12 +396,12 @@ fn div(x: i32, y: i32) -> MyResult<i32> {
fn test_wrap_return_type_not_applicable_when_expr_type_does_not_match_ok_type() {
check_no_diagnostics(
r#"
//- /main.rs
//- /main.rs crate:main deps:core
use core::result::Result::{self, Ok, Err};
fn foo() -> Result<(), i32> { 0 }
//- /core/lib.rs
//- /core/lib.rs crate:core
pub mod result {
pub enum Result<T, E> { Ok(T), Err(E) }
}
@ -418,14 +413,14 @@ pub mod result {
fn test_wrap_return_type_not_applicable_when_return_type_is_not_result() {
check_no_diagnostics(
r#"
//- /main.rs
//- /main.rs crate:main deps:core
use core::result::Result::{self, Ok, Err};
enum SomeOtherEnum { Ok(i32), Err(String) }
fn foo() -> SomeOtherEnum { 0 }
//- /core/lib.rs
//- /core/lib.rs crate:core
pub mod result {
pub enum Result<T, E> { Ok(T), Err(E) }
}
@ -567,7 +562,7 @@ fn test_fn() {
file_system_edits: [
CreateFile {
anchor: FileId(
1,
0,
),
dst: "foo.rs",
},
@ -787,7 +782,7 @@ struct Foo {
let mut config = DiagnosticsConfig::default();
config.disabled.insert("unresolved-module".into());
let (analysis, file_id) = single_file(r#"mod foo;"#);
let (analysis, file_id) = fixture::file(r#"mod foo;"#);
let diagnostics = analysis.diagnostics(&config, file_id).unwrap();
assert!(diagnostics.is_empty());

View file

@ -423,11 +423,11 @@ pub(crate) fn description_from_symbol(db: &RootDatabase, symbol: &FileSymbol) ->
mod tests {
use expect_test::expect;
use crate::{mock_analysis::single_file, Query};
use crate::{fixture, Query};
#[test]
fn test_nav_for_symbol() {
let (analysis, _) = single_file(
let (analysis, _) = fixture::file(
r#"
enum FooInner { }
fn foo() { enum FooInner { } }
@ -439,7 +439,7 @@ fn foo() { enum FooInner { } }
[
NavigationTarget {
file_id: FileId(
1,
0,
),
full_range: 0..17,
focus_range: Some(
@ -455,7 +455,7 @@ fn foo() { enum FooInner { } }
},
NavigationTarget {
file_id: FileId(
1,
0,
),
full_range: 29..46,
focus_range: Some(
@ -478,7 +478,7 @@ fn foo() { enum FooInner { } }
#[test]
fn test_world_symbols_are_case_sensitive() {
let (analysis, _) = single_file(
let (analysis, _) = fixture::file(
r#"
fn foo() {}
struct Foo;

View file

@ -122,10 +122,10 @@ fn insert_whitespaces(syn: SyntaxNode) -> String {
mod tests {
use expect_test::{expect, Expect};
use crate::mock_analysis::analysis_and_position;
use crate::fixture;
fn check(ra_fixture: &str, expect: Expect) {
let (analysis, pos) = analysis_and_position(ra_fixture);
let (analysis, pos) = fixture::position(ra_fixture);
let expansion = analysis.expand_macro(pos).unwrap().unwrap();
let actual = format!("{}\n{}", expansion.name, expansion.expansion);
expect.assert_eq(&actual);

View file

@ -315,12 +315,12 @@ fn adj_comments(comment: &ast::Comment, dir: Direction) -> ast::Comment {
#[cfg(test)]
mod tests {
use crate::mock_analysis::analysis_and_position;
use crate::fixture;
use super::*;
fn do_check(before: &str, afters: &[&str]) {
let (analysis, position) = analysis_and_position(&before);
let (analysis, position) = fixture::position(&before);
let before = analysis.file_text(position.file_id).unwrap();
let range = TextRange::empty(position.offset);
let mut frange = FileRange { file_id: position.file_id, range };

70
crates/ide/src/fixture.rs Normal file
View file

@ -0,0 +1,70 @@
//! Utilities for creating `Analysis` instances for tests.
use base_db::fixture::ChangeFixture;
use test_utils::{extract_annotations, RangeOrOffset};
use crate::{Analysis, AnalysisHost, FileId, FilePosition, FileRange};
/// Creates analysis for a single file.
pub(crate) fn file(ra_fixture: &str) -> (Analysis, FileId) {
let mut host = AnalysisHost::default();
let change_fixture = ChangeFixture::parse(ra_fixture);
host.db.apply_change(change_fixture.change);
(host.analysis(), change_fixture.files[0])
}
/// Creates analysis for many files.
pub(crate) fn files(ra_fixture: &str) -> (Analysis, Vec<FileId>) {
let mut host = AnalysisHost::default();
let change_fixture = ChangeFixture::parse(ra_fixture);
host.db.apply_change(change_fixture.change);
(host.analysis(), change_fixture.files)
}
/// Creates analysis from a multi-file fixture, returns positions marked with <|>.
pub(crate) fn position(ra_fixture: &str) -> (Analysis, FilePosition) {
let mut host = AnalysisHost::default();
let change_fixture = ChangeFixture::parse(ra_fixture);
host.db.apply_change(change_fixture.change);
let (file_id, range_or_offset) = change_fixture.file_position.expect("expected a marker (<|>)");
let offset = match range_or_offset {
RangeOrOffset::Range(_) => panic!(),
RangeOrOffset::Offset(it) => it,
};
(host.analysis(), FilePosition { file_id, offset })
}
/// Creates analysis for a single file, returns range marked with a pair of <|>.
pub(crate) fn range(ra_fixture: &str) -> (Analysis, FileRange) {
let mut host = AnalysisHost::default();
let change_fixture = ChangeFixture::parse(ra_fixture);
host.db.apply_change(change_fixture.change);
let (file_id, range_or_offset) = change_fixture.file_position.expect("expected a marker (<|>)");
let range = match range_or_offset {
RangeOrOffset::Range(it) => it,
RangeOrOffset::Offset(_) => panic!(),
};
(host.analysis(), FileRange { file_id, range })
}
/// Creates analysis from a multi-file fixture, returns positions marked with <|>.
pub(crate) fn annotations(ra_fixture: &str) -> (Analysis, FilePosition, Vec<(FileRange, String)>) {
let mut host = AnalysisHost::default();
let change_fixture = ChangeFixture::parse(ra_fixture);
host.db.apply_change(change_fixture.change);
let (file_id, range_or_offset) = change_fixture.file_position.expect("expected a marker (<|>)");
let offset = match range_or_offset {
RangeOrOffset::Range(_) => panic!(),
RangeOrOffset::Offset(it) => it,
};
let annotations = change_fixture
.files
.iter()
.flat_map(|&file_id| {
let file_text = host.analysis().file_text(file_id).unwrap();
let annotations = extract_annotations(&file_text);
annotations.into_iter().map(move |(range, data)| (FileRange { file_id, range }, data))
})
.collect();
(host.analysis(), FilePosition { file_id, offset }, annotations)
}

View file

@ -25,15 +25,14 @@ fn method_range(item: SyntaxNode, file_id: FileId) -> Option<FileRange> {
#[cfg(test)]
mod tests {
use crate::mock_analysis::analysis_and_position;
use crate::fixture;
use crate::{FileRange, TextSize};
use std::ops::RangeInclusive;
#[test]
fn test_find_all_methods() {
let (analysis, pos) = analysis_and_position(
let (analysis, pos) = fixture::position(
r#"
//- /lib.rs
fn private_fn() {<|>}
pub fn pub_fn() {}
@ -48,9 +47,8 @@ mod tests {
#[test]
fn test_find_trait_methods() {
let (analysis, pos) = analysis_and_position(
let (analysis, pos) = fixture::position(
r#"
//- /lib.rs
trait Foo {
fn bar() {<|>}
fn baz() {}
@ -64,7 +62,7 @@ mod tests {
#[test]
fn test_skip_tests() {
let (analysis, pos) = analysis_and_position(
let (analysis, pos) = fixture::position(
r#"
//- /lib.rs
#[test]

View file

@ -103,12 +103,11 @@ mod tests {
use base_db::FileRange;
use syntax::{TextRange, TextSize};
use crate::mock_analysis::MockAnalysis;
use crate::fixture;
fn check(ra_fixture: &str) {
let (mock, position) = MockAnalysis::with_files_and_position(ra_fixture);
let (mut expected, data) = mock.annotation();
let analysis = mock.analysis();
let (analysis, position, mut annotations) = fixture::annotations(ra_fixture);
let (mut expected, data) = annotations.pop().unwrap();
match data.as_str() {
"" => (),
"file" => {
@ -133,9 +132,9 @@ mod tests {
fn goto_def_for_extern_crate() {
check(
r#"
//- /main.rs
//- /main.rs crate:main deps:std
extern crate std<|>;
//- /std/lib.rs
//- /std/lib.rs crate:std
// empty
//^ file
"#,
@ -146,9 +145,9 @@ mod tests {
fn goto_def_for_renamed_extern_crate() {
check(
r#"
//- /main.rs
//- /main.rs crate:main deps:std
extern crate std as abc<|>;
//- /std/lib.rs
//- /std/lib.rs crate:std
// empty
//^ file
"#,
@ -342,10 +341,10 @@ fn bar() {
fn goto_def_for_use_alias() {
check(
r#"
//- /lib.rs
//- /lib.rs crate:main deps:foo
use foo as bar<|>;
//- /foo/lib.rs
//- /foo/lib.rs crate:foo
// empty
//^ file
"#,
@ -356,10 +355,10 @@ use foo as bar<|>;
fn goto_def_for_use_alias_foo_macro() {
check(
r#"
//- /lib.rs
//- /lib.rs crate:main deps:foo
use foo::foo as bar<|>;
//- /foo/lib.rs
//- /foo/lib.rs crate:foo
#[macro_export]
macro_rules! foo { () => { () } }
//^^^
@ -371,7 +370,6 @@ macro_rules! foo { () => { () } }
fn goto_def_for_methods() {
check(
r#"
//- /lib.rs
struct Foo;
impl Foo {
fn frobnicate(&self) { }

View file

@ -76,12 +76,10 @@ fn impls_for_trait(
mod tests {
use base_db::FileRange;
use crate::mock_analysis::MockAnalysis;
use crate::fixture;
fn check(ra_fixture: &str) {
let (mock, position) = MockAnalysis::with_files_and_position(ra_fixture);
let annotations = mock.annotations();
let analysis = mock.analysis();
let (analysis, position, annotations) = fixture::annotations(ra_fixture);
let navs = analysis.goto_implementation(position).unwrap().unwrap().info;

View file

@ -56,13 +56,12 @@ fn pick_best(tokens: TokenAtOffset<SyntaxToken>) -> Option<SyntaxToken> {
mod tests {
use base_db::FileRange;
use crate::mock_analysis::MockAnalysis;
use crate::fixture;
fn check(ra_fixture: &str) {
let (mock, position) = MockAnalysis::with_files_and_position(ra_fixture);
let (expected, data) = mock.annotation();
let (analysis, position, mut annotations) = fixture::annotations(ra_fixture);
let (expected, data) = annotations.pop().unwrap();
assert!(data.is_empty());
let analysis = mock.analysis();
let mut navs = analysis.goto_type_definition(position).unwrap().unwrap().info;
assert_eq!(navs.len(), 1);

View file

@ -377,17 +377,17 @@ mod tests {
use base_db::FileLoader;
use expect_test::{expect, Expect};
use crate::mock_analysis::analysis_and_position;
use crate::fixture;
use super::*;
fn check_hover_no_result(ra_fixture: &str) {
let (analysis, position) = analysis_and_position(ra_fixture);
let (analysis, position) = fixture::position(ra_fixture);
assert!(analysis.hover(position, true).unwrap().is_none());
}
fn check(ra_fixture: &str, expect: Expect) {
let (analysis, position) = analysis_and_position(ra_fixture);
let (analysis, position) = fixture::position(ra_fixture);
let hover = analysis.hover(position, true).unwrap().unwrap();
let content = analysis.db.file_text(position.file_id);
@ -398,7 +398,7 @@ mod tests {
}
fn check_hover_no_links(ra_fixture: &str, expect: Expect) {
let (analysis, position) = analysis_and_position(ra_fixture);
let (analysis, position) = fixture::position(ra_fixture);
let hover = analysis.hover(position, false).unwrap().unwrap();
let content = analysis.db.file_text(position.file_id);
@ -409,7 +409,7 @@ mod tests {
}
fn check_actions(ra_fixture: &str, expect: Expect) {
let (analysis, position) = analysis_and_position(ra_fixture);
let (analysis, position) = fixture::position(ra_fixture);
let hover = analysis.hover(position, true).unwrap().unwrap();
expect.assert_debug_eq(&hover.info.actions)
}
@ -963,7 +963,7 @@ impl Thing {
"#]],
)
} /* FIXME: revive these tests
let (analysis, position) = analysis_and_position(
let (analysis, position) = fixture::position(
"
struct Thing { x: u32 }
impl Thing {
@ -977,7 +977,7 @@ impl Thing {
let hover = analysis.hover(position).unwrap().unwrap();
assert_eq!(trim_markup(&hover.info.markup.as_str()), ("Thing"));
let (analysis, position) = analysis_and_position(
let (analysis, position) = fixture::position(
"
enum Thing { A }
impl Thing {
@ -990,7 +990,7 @@ impl Thing {
let hover = analysis.hover(position).unwrap().unwrap();
assert_eq!(trim_markup(&hover.info.markup.as_str()), ("enum Thing"));
let (analysis, position) = analysis_and_position(
let (analysis, position) = fixture::position(
"
enum Thing { A }
impl Thing {
@ -1275,7 +1275,7 @@ fn bar() { fo<|>o(); }
Implementaion(
FilePosition {
file_id: FileId(
1,
0,
),
offset: 13,
},
@ -1289,9 +1289,9 @@ fn bar() { fo<|>o(); }
fn test_hover_extern_crate() {
check(
r#"
//- /main.rs
//- /main.rs crate:main deps:std
extern crate st<|>d;
//- /std/lib.rs
//- /std/lib.rs crate:std
//! Standard library for this test
//!
//! Printed?
@ -1307,9 +1307,9 @@ extern crate st<|>d;
);
check(
r#"
//- /main.rs
//- /main.rs crate:main deps:std
extern crate std as ab<|>c;
//- /std/lib.rs
//- /std/lib.rs crate:std
//! Standard library for this test
//!
//! Printed?
@ -1989,7 +1989,7 @@ fn foo() { let bar = Bar; bar.fo<|>o(); }
Implementaion(
FilePosition {
file_id: FileId(
1,
0,
),
offset: 6,
},
@ -2008,7 +2008,7 @@ fn foo() { let bar = Bar; bar.fo<|>o(); }
Implementaion(
FilePosition {
file_id: FileId(
1,
0,
),
offset: 7,
},
@ -2027,7 +2027,7 @@ fn foo() { let bar = Bar; bar.fo<|>o(); }
Implementaion(
FilePosition {
file_id: FileId(
1,
0,
),
offset: 6,
},
@ -2046,7 +2046,7 @@ fn foo() { let bar = Bar; bar.fo<|>o(); }
Implementaion(
FilePosition {
file_id: FileId(
1,
0,
),
offset: 5,
},
@ -2069,7 +2069,7 @@ fn foo_<|>test() {}
Runnable {
nav: NavigationTarget {
file_id: FileId(
1,
0,
),
full_range: 0..24,
focus_range: Some(
@ -2112,7 +2112,7 @@ mod tests<|> {
Runnable {
nav: NavigationTarget {
file_id: FileId(
1,
0,
),
full_range: 0..46,
focus_range: Some(
@ -2151,7 +2151,7 @@ fn main() { let s<|>t = S{ f1:0 }; }
mod_path: "test::S",
nav: NavigationTarget {
file_id: FileId(
1,
0,
),
full_range: 0..19,
focus_range: Some(
@ -2190,7 +2190,7 @@ fn main() { let s<|>t = S{ f1:Arg(0) }; }
mod_path: "test::S",
nav: NavigationTarget {
file_id: FileId(
1,
0,
),
full_range: 17..37,
focus_range: Some(
@ -2209,7 +2209,7 @@ fn main() { let s<|>t = S{ f1:Arg(0) }; }
mod_path: "test::Arg",
nav: NavigationTarget {
file_id: FileId(
1,
0,
),
full_range: 0..16,
focus_range: Some(
@ -2248,7 +2248,7 @@ fn main() { let s<|>t = S{ f1: S{ f1: Arg(0) } }; }
mod_path: "test::S",
nav: NavigationTarget {
file_id: FileId(
1,
0,
),
full_range: 17..37,
focus_range: Some(
@ -2267,7 +2267,7 @@ fn main() { let s<|>t = S{ f1: S{ f1: Arg(0) } }; }
mod_path: "test::Arg",
nav: NavigationTarget {
file_id: FileId(
1,
0,
),
full_range: 0..16,
focus_range: Some(
@ -2309,7 +2309,7 @@ fn main() { let s<|>t = (A(1), B(2), M::C(3) ); }
mod_path: "test::A",
nav: NavigationTarget {
file_id: FileId(
1,
0,
),
full_range: 0..14,
focus_range: Some(
@ -2328,7 +2328,7 @@ fn main() { let s<|>t = (A(1), B(2), M::C(3) ); }
mod_path: "test::B",
nav: NavigationTarget {
file_id: FileId(
1,
0,
),
full_range: 15..29,
focus_range: Some(
@ -2347,7 +2347,7 @@ fn main() { let s<|>t = (A(1), B(2), M::C(3) ); }
mod_path: "test::M::C",
nav: NavigationTarget {
file_id: FileId(
1,
0,
),
full_range: 42..60,
focus_range: Some(
@ -2386,7 +2386,7 @@ fn main() { let s<|>t = foo(); }
mod_path: "test::Foo",
nav: NavigationTarget {
file_id: FileId(
1,
0,
),
full_range: 0..12,
focus_range: Some(
@ -2426,7 +2426,7 @@ fn main() { let s<|>t = foo(); }
mod_path: "test::Foo",
nav: NavigationTarget {
file_id: FileId(
1,
0,
),
full_range: 0..15,
focus_range: Some(
@ -2445,7 +2445,7 @@ fn main() { let s<|>t = foo(); }
mod_path: "test::S",
nav: NavigationTarget {
file_id: FileId(
1,
0,
),
full_range: 16..25,
focus_range: Some(
@ -2485,7 +2485,7 @@ fn main() { let s<|>t = foo(); }
mod_path: "test::Foo",
nav: NavigationTarget {
file_id: FileId(
1,
0,
),
full_range: 0..12,
focus_range: Some(
@ -2504,7 +2504,7 @@ fn main() { let s<|>t = foo(); }
mod_path: "test::Bar",
nav: NavigationTarget {
file_id: FileId(
1,
0,
),
full_range: 13..25,
focus_range: Some(
@ -2547,7 +2547,7 @@ fn main() { let s<|>t = foo(); }
mod_path: "test::Foo",
nav: NavigationTarget {
file_id: FileId(
1,
0,
),
full_range: 0..15,
focus_range: Some(
@ -2566,7 +2566,7 @@ fn main() { let s<|>t = foo(); }
mod_path: "test::Bar",
nav: NavigationTarget {
file_id: FileId(
1,
0,
),
full_range: 16..31,
focus_range: Some(
@ -2585,7 +2585,7 @@ fn main() { let s<|>t = foo(); }
mod_path: "test::S1",
nav: NavigationTarget {
file_id: FileId(
1,
0,
),
full_range: 32..44,
focus_range: Some(
@ -2604,7 +2604,7 @@ fn main() { let s<|>t = foo(); }
mod_path: "test::S2",
nav: NavigationTarget {
file_id: FileId(
1,
0,
),
full_range: 45..57,
focus_range: Some(
@ -2641,7 +2641,7 @@ fn foo(ar<|>g: &impl Foo) {}
mod_path: "test::Foo",
nav: NavigationTarget {
file_id: FileId(
1,
0,
),
full_range: 0..12,
focus_range: Some(
@ -2681,7 +2681,7 @@ fn foo(ar<|>g: &impl Foo + Bar<S>) {}
mod_path: "test::Foo",
nav: NavigationTarget {
file_id: FileId(
1,
0,
),
full_range: 0..12,
focus_range: Some(
@ -2700,7 +2700,7 @@ fn foo(ar<|>g: &impl Foo + Bar<S>) {}
mod_path: "test::Bar",
nav: NavigationTarget {
file_id: FileId(
1,
0,
),
full_range: 13..28,
focus_range: Some(
@ -2719,7 +2719,7 @@ fn foo(ar<|>g: &impl Foo + Bar<S>) {}
mod_path: "test::S",
nav: NavigationTarget {
file_id: FileId(
1,
0,
),
full_range: 29..39,
focus_range: Some(
@ -2764,7 +2764,7 @@ mod future {
mod_path: "test::future::Future",
nav: NavigationTarget {
file_id: FileId(
1,
0,
),
full_range: 101..163,
focus_range: Some(
@ -2783,7 +2783,7 @@ mod future {
mod_path: "test::S",
nav: NavigationTarget {
file_id: FileId(
1,
0,
),
full_range: 0..9,
focus_range: Some(
@ -2821,7 +2821,7 @@ fn foo(ar<|>g: &impl Foo<S>) {}
mod_path: "test::Foo",
nav: NavigationTarget {
file_id: FileId(
1,
0,
),
full_range: 0..15,
focus_range: Some(
@ -2840,7 +2840,7 @@ fn foo(ar<|>g: &impl Foo<S>) {}
mod_path: "test::S",
nav: NavigationTarget {
file_id: FileId(
1,
0,
),
full_range: 16..27,
focus_range: Some(
@ -2883,7 +2883,7 @@ fn main() { let s<|>t = foo(); }
mod_path: "test::B",
nav: NavigationTarget {
file_id: FileId(
1,
0,
),
full_range: 42..55,
focus_range: Some(
@ -2902,7 +2902,7 @@ fn main() { let s<|>t = foo(); }
mod_path: "test::Foo",
nav: NavigationTarget {
file_id: FileId(
1,
0,
),
full_range: 0..12,
focus_range: Some(
@ -2939,7 +2939,7 @@ fn foo(ar<|>g: &dyn Foo) {}
mod_path: "test::Foo",
nav: NavigationTarget {
file_id: FileId(
1,
0,
),
full_range: 0..12,
focus_range: Some(
@ -2977,7 +2977,7 @@ fn foo(ar<|>g: &dyn Foo<S>) {}
mod_path: "test::Foo",
nav: NavigationTarget {
file_id: FileId(
1,
0,
),
full_range: 0..15,
focus_range: Some(
@ -2996,7 +2996,7 @@ fn foo(ar<|>g: &dyn Foo<S>) {}
mod_path: "test::S",
nav: NavigationTarget {
file_id: FileId(
1,
0,
),
full_range: 16..27,
focus_range: Some(
@ -3037,7 +3037,7 @@ fn foo(a<|>rg: &impl ImplTrait<B<dyn DynTrait<B<S>>>>) {}
mod_path: "test::ImplTrait",
nav: NavigationTarget {
file_id: FileId(
1,
0,
),
full_range: 0..21,
focus_range: Some(
@ -3056,7 +3056,7 @@ fn foo(a<|>rg: &impl ImplTrait<B<dyn DynTrait<B<S>>>>) {}
mod_path: "test::B",
nav: NavigationTarget {
file_id: FileId(
1,
0,
),
full_range: 43..57,
focus_range: Some(
@ -3075,7 +3075,7 @@ fn foo(a<|>rg: &impl ImplTrait<B<dyn DynTrait<B<S>>>>) {}
mod_path: "test::DynTrait",
nav: NavigationTarget {
file_id: FileId(
1,
0,
),
full_range: 22..42,
focus_range: Some(
@ -3094,7 +3094,7 @@ fn foo(a<|>rg: &impl ImplTrait<B<dyn DynTrait<B<S>>>>) {}
mod_path: "test::S",
nav: NavigationTarget {
file_id: FileId(
1,
0,
),
full_range: 58..69,
focus_range: Some(
@ -3142,7 +3142,7 @@ fn main() { let s<|>t = test().get(); }
mod_path: "test::Foo",
nav: NavigationTarget {
file_id: FileId(
1,
0,
),
full_range: 0..62,
focus_range: Some(

View file

@ -339,14 +339,14 @@ mod tests {
use expect_test::{expect, Expect};
use test_utils::extract_annotations;
use crate::{inlay_hints::InlayHintsConfig, mock_analysis::single_file};
use crate::{fixture, inlay_hints::InlayHintsConfig};
fn check(ra_fixture: &str) {
check_with_config(InlayHintsConfig::default(), ra_fixture);
}
fn check_with_config(config: InlayHintsConfig, ra_fixture: &str) {
let (analysis, file_id) = single_file(ra_fixture);
let (analysis, file_id) = fixture::file(ra_fixture);
let expected = extract_annotations(&*analysis.file_text(file_id).unwrap());
let inlay_hints = analysis.inlay_hints(file_id, &config).unwrap();
let actual =
@ -355,7 +355,7 @@ mod tests {
}
fn check_expect(config: InlayHintsConfig, ra_fixture: &str, expect: Expect) {
let (analysis, file_id) = single_file(ra_fixture);
let (analysis, file_id) = fixture::file(ra_fixture);
let inlay_hints = analysis.inlay_hints(file_id, &config).unwrap();
expect.assert_debug_eq(&inlay_hints)
}

View file

@ -16,7 +16,7 @@ macro_rules! eprintln {
}
#[cfg(test)]
mod mock_analysis;
mod fixture;
mod markup;
mod prime_caches;
@ -87,12 +87,11 @@ pub use assists::{
utils::MergeBehaviour, Assist, AssistConfig, AssistId, AssistKind, ResolvedAssist,
};
pub use base_db::{
Canceled, CrateGraph, CrateId, Edition, FileId, FilePosition, FileRange, SourceRoot,
Canceled, Change, CrateGraph, CrateId, Edition, FileId, FilePosition, FileRange, SourceRoot,
SourceRootId,
};
pub use hir::{Documentation, Semantics};
pub use ide_db::{
change::AnalysisChange,
label::Label,
line_index::{LineCol, LineIndex},
search::SearchScope,
@ -141,7 +140,7 @@ impl AnalysisHost {
/// Applies changes to the current state of the world. If there are
/// outstanding snapshots, they will be canceled.
pub fn apply_change(&mut self, change: AnalysisChange) {
pub fn apply_change(&mut self, change: Change) {
self.db.apply_change(change)
}
@ -195,7 +194,7 @@ impl Analysis {
file_set.insert(file_id, VfsPath::new_virtual_path("/main.rs".to_string()));
let source_root = SourceRoot::new_local(file_set);
let mut change = AnalysisChange::new();
let mut change = Change::new();
change.set_roots(vec![source_root]);
let mut crate_graph = CrateGraph::default();
// FIXME: cfg options

View file

@ -1,176 +0,0 @@
//! FIXME: write short doc here
use std::sync::Arc;
use base_db::{CrateName, FileSet, SourceRoot, VfsPath};
use cfg::CfgOptions;
use test_utils::{
extract_annotations, extract_range_or_offset, Fixture, RangeOrOffset, CURSOR_MARKER,
};
use crate::{
Analysis, AnalysisChange, AnalysisHost, CrateGraph, Edition, FileId, FilePosition, FileRange,
};
/// Mock analysis is used in test to bootstrap an AnalysisHost/Analysis
/// from a set of in-memory files.
#[derive(Debug, Default)]
pub(crate) struct MockAnalysis {
files: Vec<Fixture>,
}
impl MockAnalysis {
/// Creates `MockAnalysis` using a fixture data in the following format:
///
/// ```not_rust
/// //- /main.rs
/// mod foo;
/// fn main() {}
///
/// //- /foo.rs
/// struct Baz;
/// ```
pub(crate) fn with_files(ra_fixture: &str) -> MockAnalysis {
let (res, pos) = MockAnalysis::with_fixture(ra_fixture);
assert!(pos.is_none());
res
}
/// Same as `with_files`, but requires that a single file contains a `<|>` marker,
/// whose position is also returned.
pub(crate) fn with_files_and_position(fixture: &str) -> (MockAnalysis, FilePosition) {
let (res, position) = MockAnalysis::with_fixture(fixture);
let (file_id, range_or_offset) = position.expect("expected a marker (<|>)");
let offset = match range_or_offset {
RangeOrOffset::Range(_) => panic!(),
RangeOrOffset::Offset(it) => it,
};
(res, FilePosition { file_id, offset })
}
fn with_fixture(fixture: &str) -> (MockAnalysis, Option<(FileId, RangeOrOffset)>) {
let mut position = None;
let mut res = MockAnalysis::default();
for mut entry in Fixture::parse(fixture) {
if entry.text.contains(CURSOR_MARKER) {
assert!(position.is_none(), "only one marker (<|>) per fixture is allowed");
let (range_or_offset, text) = extract_range_or_offset(&entry.text);
entry.text = text;
let file_id = res.add_file_fixture(entry);
position = Some((file_id, range_or_offset));
} else {
res.add_file_fixture(entry);
}
}
(res, position)
}
fn add_file_fixture(&mut self, fixture: Fixture) -> FileId {
let file_id = FileId((self.files.len() + 1) as u32);
self.files.push(fixture);
file_id
}
pub(crate) fn id_of(&self, path: &str) -> FileId {
let (file_id, _) =
self.files().find(|(_, data)| path == data.path).expect("no file in this mock");
file_id
}
pub(crate) fn annotations(&self) -> Vec<(FileRange, String)> {
self.files()
.flat_map(|(file_id, fixture)| {
let annotations = extract_annotations(&fixture.text);
annotations
.into_iter()
.map(move |(range, data)| (FileRange { file_id, range }, data))
})
.collect()
}
pub(crate) fn files(&self) -> impl Iterator<Item = (FileId, &Fixture)> + '_ {
self.files.iter().enumerate().map(|(idx, fixture)| (FileId(idx as u32 + 1), fixture))
}
pub(crate) fn annotation(&self) -> (FileRange, String) {
let mut all = self.annotations();
assert_eq!(all.len(), 1);
all.pop().unwrap()
}
pub(crate) fn analysis_host(self) -> AnalysisHost {
let mut host = AnalysisHost::default();
let mut change = AnalysisChange::new();
let mut file_set = FileSet::default();
let mut crate_graph = CrateGraph::default();
let mut root_crate = None;
for (i, data) in self.files.into_iter().enumerate() {
let path = data.path;
assert!(path.starts_with('/'));
let mut cfg = CfgOptions::default();
data.cfg_atoms.iter().for_each(|it| cfg.insert_atom(it.into()));
data.cfg_key_values.iter().for_each(|(k, v)| cfg.insert_key_value(k.into(), v.into()));
let edition: Edition =
data.edition.and_then(|it| it.parse().ok()).unwrap_or(Edition::Edition2018);
let file_id = FileId(i as u32 + 1);
let env = data.env.into_iter().collect();
if path == "/lib.rs" || path == "/main.rs" {
root_crate = Some(crate_graph.add_crate_root(
file_id,
edition,
Some("test".to_string()),
cfg,
env,
Default::default(),
));
} else if path.ends_with("/lib.rs") {
let base = &path[..path.len() - "/lib.rs".len()];
let crate_name = &base[base.rfind('/').unwrap() + '/'.len_utf8()..];
let other_crate = crate_graph.add_crate_root(
file_id,
edition,
Some(crate_name.to_string()),
cfg,
env,
Default::default(),
);
if let Some(root_crate) = root_crate {
crate_graph
.add_dep(root_crate, CrateName::new(crate_name).unwrap(), other_crate)
.unwrap();
}
}
let path = VfsPath::new_virtual_path(path.to_string());
file_set.insert(file_id, path);
change.change_file(file_id, Some(Arc::new(data.text).to_owned()));
}
change.set_crate_graph(crate_graph);
change.set_roots(vec![SourceRoot::new_local(file_set)]);
host.apply_change(change);
host
}
pub(crate) fn analysis(self) -> Analysis {
self.analysis_host().analysis()
}
}
/// Creates analysis from a multi-file fixture, returns positions marked with <|>.
pub(crate) fn analysis_and_position(ra_fixture: &str) -> (Analysis, FilePosition) {
let (mock, position) = MockAnalysis::with_files_and_position(ra_fixture);
(mock.analysis(), position)
}
/// Creates analysis for a single file.
pub(crate) fn single_file(ra_fixture: &str) -> (Analysis, FileId) {
let mock = MockAnalysis::with_files(ra_fixture);
let file_id = mock.id_of("/main.rs");
(mock.analysis(), file_id)
}
/// Creates analysis for a single file, returns range marked with a pair of <|>.
pub(crate) fn analysis_and_range(ra_fixture: &str) -> (Analysis, FileRange) {
let (res, position) = MockAnalysis::with_fixture(ra_fixture);
let (file_id, range_or_offset) = position.expect("expected a marker (<|>)");
let range = match range_or_offset {
RangeOrOffset::Range(it) => it,
RangeOrOffset::Offset(_) => panic!(),
};
(res.analysis(), FileRange { file_id, range })
}

View file

@ -63,19 +63,13 @@ pub(crate) fn crate_for(db: &RootDatabase, file_id: FileId) -> Vec<CrateId> {
#[cfg(test)]
mod tests {
use base_db::Env;
use cfg::CfgOptions;
use test_utils::mark;
use crate::{
mock_analysis::{analysis_and_position, MockAnalysis},
AnalysisChange, CrateGraph,
Edition::Edition2018,
};
use crate::fixture::{self};
#[test]
fn test_resolve_parent_module() {
let (analysis, pos) = analysis_and_position(
let (analysis, pos) = fixture::position(
"
//- /lib.rs
mod foo;
@ -84,13 +78,13 @@ mod tests {
",
);
let nav = analysis.parent_module(pos).unwrap().pop().unwrap();
nav.assert_match("foo MODULE FileId(1) 0..8");
nav.assert_match("foo MODULE FileId(0) 0..8");
}
#[test]
fn test_resolve_parent_module_on_module_decl() {
mark::check!(test_resolve_parent_module_on_module_decl);
let (analysis, pos) = analysis_and_position(
let (analysis, pos) = fixture::position(
"
//- /lib.rs
mod foo;
@ -103,12 +97,12 @@ mod tests {
",
);
let nav = analysis.parent_module(pos).unwrap().pop().unwrap();
nav.assert_match("foo MODULE FileId(1) 0..8");
nav.assert_match("foo MODULE FileId(0) 0..8");
}
#[test]
fn test_resolve_parent_module_for_inline() {
let (analysis, pos) = analysis_and_position(
let (analysis, pos) = fixture::position(
"
//- /lib.rs
mod foo {
@ -119,37 +113,19 @@ mod tests {
",
);
let nav = analysis.parent_module(pos).unwrap().pop().unwrap();
nav.assert_match("baz MODULE FileId(1) 32..44");
nav.assert_match("baz MODULE FileId(0) 32..44");
}
#[test]
fn test_resolve_crate_root() {
let mock = MockAnalysis::with_files(
let (analysis, file_id) = fixture::file(
r#"
//- /bar.rs
//- /main.rs
mod foo;
//- /foo.rs
// empty
<|>
"#,
);
let root_file = mock.id_of("/bar.rs");
let mod_file = mock.id_of("/foo.rs");
let mut host = mock.analysis_host();
assert!(host.analysis().crate_for(mod_file).unwrap().is_empty());
let mut crate_graph = CrateGraph::default();
let crate_id = crate_graph.add_crate_root(
root_file,
Edition2018,
None,
CfgOptions::default(),
Env::default(),
Default::default(),
);
let mut change = AnalysisChange::new();
change.set_crate_graph(crate_graph);
host.apply_change(change);
assert_eq!(host.analysis().crate_for(mod_file).unwrap(), vec![crate_id]);
assert_eq!(analysis.crate_for(file_id).unwrap().len(), 1);
}
}

View file

@ -190,10 +190,11 @@ fn get_struct_def_name_for_struct_literal_search(
#[cfg(test)]
mod tests {
use base_db::FileId;
use expect_test::{expect, Expect};
use stdx::format_to;
use crate::{mock_analysis::MockAnalysis, SearchScope};
use crate::{fixture, SearchScope};
#[test]
fn test_struct_literal_after_space() {
@ -211,9 +212,9 @@ fn main() {
}
"#,
expect![[r#"
Foo STRUCT FileId(1) 0..26 7..10 Other
Foo STRUCT FileId(0) 0..26 7..10 Other
FileId(1) 101..104 StructLiteral
FileId(0) 101..104 StructLiteral
"#]],
);
}
@ -229,10 +230,10 @@ struct Foo<|> {}
}
"#,
expect![[r#"
Foo STRUCT FileId(1) 0..13 7..10 Other
Foo STRUCT FileId(0) 0..13 7..10 Other
FileId(1) 41..44 Other
FileId(1) 54..57 StructLiteral
FileId(0) 41..44 Other
FileId(0) 54..57 StructLiteral
"#]],
);
}
@ -248,9 +249,9 @@ struct Foo<T> <|>{}
}
"#,
expect![[r#"
Foo STRUCT FileId(1) 0..16 7..10 Other
Foo STRUCT FileId(0) 0..16 7..10 Other
FileId(1) 64..67 StructLiteral
FileId(0) 64..67 StructLiteral
"#]],
);
}
@ -267,9 +268,9 @@ fn main() {
}
"#,
expect![[r#"
Foo STRUCT FileId(1) 0..16 7..10 Other
Foo STRUCT FileId(0) 0..16 7..10 Other
FileId(1) 54..57 StructLiteral
FileId(0) 54..57 StructLiteral
"#]],
);
}
@ -290,12 +291,12 @@ fn main() {
i = 5;
}"#,
expect![[r#"
i IDENT_PAT FileId(1) 24..25 Other Write
i IDENT_PAT FileId(0) 24..25 Other Write
FileId(1) 50..51 Other Write
FileId(1) 54..55 Other Read
FileId(1) 76..77 Other Write
FileId(1) 94..95 Other Write
FileId(0) 50..51 Other Write
FileId(0) 54..55 Other Read
FileId(0) 76..77 Other Write
FileId(0) 94..95 Other Write
"#]],
);
}
@ -314,10 +315,10 @@ fn bar() {
}
"#,
expect![[r#"
spam IDENT_PAT FileId(1) 19..23 Other
spam IDENT_PAT FileId(0) 19..23 Other
FileId(1) 34..38 Other Read
FileId(1) 41..45 Other Read
FileId(0) 34..38 Other Read
FileId(0) 41..45 Other Read
"#]],
);
}
@ -329,9 +330,9 @@ fn bar() {
fn foo(i : u32) -> u32 { i<|> }
"#,
expect![[r#"
i IDENT_PAT FileId(1) 7..8 Other
i IDENT_PAT FileId(0) 7..8 Other
FileId(1) 25..26 Other Read
FileId(0) 25..26 Other Read
"#]],
);
}
@ -343,9 +344,9 @@ fn foo(i : u32) -> u32 { i<|> }
fn foo(i<|> : u32) -> u32 { i }
"#,
expect![[r#"
i IDENT_PAT FileId(1) 7..8 Other
i IDENT_PAT FileId(0) 7..8 Other
FileId(1) 25..26 Other Read
FileId(0) 25..26 Other Read
"#]],
);
}
@ -364,9 +365,9 @@ fn main(s: Foo) {
}
"#,
expect![[r#"
spam RECORD_FIELD FileId(1) 17..30 21..25 Other
spam RECORD_FIELD FileId(0) 17..30 21..25 Other
FileId(1) 67..71 Other Read
FileId(0) 67..71 Other Read
"#]],
);
}
@ -381,7 +382,7 @@ impl Foo {
}
"#,
expect![[r#"
f FN FileId(1) 27..43 30..31 Other
f FN FileId(0) 27..43 30..31 Other
"#]],
);
@ -398,7 +399,7 @@ enum Foo {
}
"#,
expect![[r#"
B VARIANT FileId(1) 22..23 22..23 Other
B VARIANT FileId(0) 22..23 22..23 Other
"#]],
);
@ -439,10 +440,10 @@ fn f() {
}
"#,
expect![[r#"
Foo STRUCT FileId(2) 17..51 28..31 Other
Foo STRUCT FileId(1) 17..51 28..31 Other
FileId(1) 53..56 StructLiteral
FileId(3) 79..82 StructLiteral
FileId(0) 53..56 StructLiteral
FileId(2) 79..82 StructLiteral
"#]],
);
}
@ -469,9 +470,9 @@ pub struct Foo {
}
"#,
expect![[r#"
foo SOURCE_FILE FileId(2) 0..35 Other
foo SOURCE_FILE FileId(1) 0..35 Other
FileId(1) 14..17 Other
FileId(0) 14..17 Other
"#]],
);
}
@ -497,10 +498,10 @@ pub(super) struct Foo<|> {
}
"#,
expect![[r#"
Foo STRUCT FileId(3) 0..41 18..21 Other
Foo STRUCT FileId(2) 0..41 18..21 Other
FileId(2) 20..23 Other
FileId(2) 47..50 StructLiteral
FileId(1) 20..23 Other
FileId(1) 47..50 StructLiteral
"#]],
);
}
@ -525,20 +526,20 @@ pub(super) struct Foo<|> {
code,
None,
expect![[r#"
quux FN FileId(1) 19..35 26..30 Other
quux FN FileId(0) 19..35 26..30 Other
FileId(1) 16..20 StructLiteral
FileId(2) 16..20 StructLiteral
FileId(3) 16..20 StructLiteral
"#]],
);
check_with_scope(
code,
Some("/bar.rs"),
Some(SearchScope::single_file(FileId(2))),
expect![[r#"
quux FN FileId(1) 19..35 26..30 Other
quux FN FileId(0) 19..35 26..30 Other
FileId(3) 16..20 StructLiteral
FileId(2) 16..20 StructLiteral
"#]],
);
}
@ -556,10 +557,10 @@ fn foo() {
}
"#,
expect![[r#"
m1 MACRO_CALL FileId(1) 0..46 29..31 Other
m1 MACRO_CALL FileId(0) 0..46 29..31 Other
FileId(1) 63..65 StructLiteral
FileId(1) 73..75 StructLiteral
FileId(0) 63..65 StructLiteral
FileId(0) 73..75 StructLiteral
"#]],
);
}
@ -574,10 +575,10 @@ fn foo() {
}
"#,
expect![[r#"
i IDENT_PAT FileId(1) 23..24 Other Write
i IDENT_PAT FileId(0) 23..24 Other Write
FileId(1) 34..35 Other Write
FileId(1) 38..39 Other Read
FileId(0) 34..35 Other Write
FileId(0) 38..39 Other Read
"#]],
);
}
@ -596,10 +597,10 @@ fn foo() {
}
"#,
expect![[r#"
f RECORD_FIELD FileId(1) 15..21 15..16 Other
f RECORD_FIELD FileId(0) 15..21 15..16 Other
FileId(1) 55..56 Other Read
FileId(1) 68..69 Other Write
FileId(0) 55..56 Other Read
FileId(0) 68..69 Other Write
"#]],
);
}
@ -614,9 +615,9 @@ fn foo() {
}
"#,
expect![[r#"
i IDENT_PAT FileId(1) 19..20 Other
i IDENT_PAT FileId(0) 19..20 Other
FileId(1) 26..27 Other Write
FileId(0) 26..27 Other Write
"#]],
);
}
@ -638,9 +639,9 @@ fn main() {
}
"#,
expect![[r#"
new FN FileId(1) 54..81 61..64 Other
new FN FileId(0) 54..81 61..64 Other
FileId(1) 126..129 StructLiteral
FileId(0) 126..129 StructLiteral
"#]],
);
}
@ -660,10 +661,10 @@ use crate::f;
fn g() { f(); }
"#,
expect![[r#"
f FN FileId(1) 22..31 25..26 Other
f FN FileId(0) 22..31 25..26 Other
FileId(2) 11..12 Other
FileId(2) 24..25 StructLiteral
FileId(1) 11..12 Other
FileId(1) 24..25 StructLiteral
"#]],
);
}
@ -672,11 +673,8 @@ fn g() { f(); }
check_with_scope(ra_fixture, None, expect)
}
fn check_with_scope(ra_fixture: &str, search_scope: Option<&str>, expect: Expect) {
let (mock_analysis, pos) = MockAnalysis::with_files_and_position(ra_fixture);
let search_scope =
search_scope.map(|path| SearchScope::single_file(mock_analysis.id_of(path)));
let analysis = mock_analysis.analysis();
fn check_with_scope(ra_fixture: &str, search_scope: Option<SearchScope>, expect: Expect) {
let (analysis, pos) = fixture::position(ra_fixture);
let refs = analysis.find_all_refs(pos, search_scope).unwrap().unwrap();
let mut actual = String::new();

View file

@ -275,11 +275,11 @@ mod tests {
use test_utils::{assert_eq_text, mark};
use text_edit::TextEdit;
use crate::{mock_analysis::analysis_and_position, FileId};
use crate::{fixture, FileId};
fn check(new_name: &str, ra_fixture_before: &str, ra_fixture_after: &str) {
let ra_fixture_after = &trim_indent(ra_fixture_after);
let (analysis, position) = analysis_and_position(ra_fixture_before);
let (analysis, position) = fixture::position(ra_fixture_before);
let source_change = analysis.rename(position, new_name).unwrap();
let mut text_edit_builder = TextEdit::builder();
let mut file_id: Option<FileId> = None;
@ -297,7 +297,7 @@ mod tests {
}
fn check_expect(new_name: &str, ra_fixture: &str, expect: Expect) {
let (analysis, position) = analysis_and_position(ra_fixture);
let (analysis, position) = fixture::position(ra_fixture);
let source_change = analysis.rename(position, new_name).unwrap().unwrap();
expect.assert_debug_eq(&source_change)
}
@ -314,7 +314,7 @@ mod tests {
#[test]
fn test_rename_to_invalid_identifier() {
let (analysis, position) = analysis_and_position(r#"fn main() { let i<|> = 1; }"#);
let (analysis, position) = fixture::position(r#"fn main() { let i<|> = 1; }"#);
let new_name = "invalid!";
let source_change = analysis.rename(position, new_name).unwrap();
assert!(source_change.is_none());
@ -602,7 +602,7 @@ mod foo<|>;
source_file_edits: [
SourceFileEdit {
file_id: FileId(
2,
1,
),
edit: TextEdit {
indels: [
@ -617,10 +617,10 @@ mod foo<|>;
file_system_edits: [
MoveFile {
src: FileId(
3,
2,
),
anchor: FileId(
3,
2,
),
dst: "foo2.rs",
},
@ -655,7 +655,7 @@ use crate::foo<|>::FooContent;
source_file_edits: [
SourceFileEdit {
file_id: FileId(
1,
0,
),
edit: TextEdit {
indels: [
@ -668,7 +668,7 @@ use crate::foo<|>::FooContent;
},
SourceFileEdit {
file_id: FileId(
3,
2,
),
edit: TextEdit {
indels: [
@ -683,10 +683,10 @@ use crate::foo<|>::FooContent;
file_system_edits: [
MoveFile {
src: FileId(
2,
1,
),
anchor: FileId(
2,
1,
),
dst: "quux.rs",
},
@ -715,7 +715,7 @@ mod fo<|>o;
source_file_edits: [
SourceFileEdit {
file_id: FileId(
1,
0,
),
edit: TextEdit {
indels: [
@ -730,10 +730,10 @@ mod fo<|>o;
file_system_edits: [
MoveFile {
src: FileId(
2,
1,
),
anchor: FileId(
2,
1,
),
dst: "../foo2/mod.rs",
},
@ -763,7 +763,7 @@ mod outer { mod fo<|>o; }
source_file_edits: [
SourceFileEdit {
file_id: FileId(
1,
0,
),
edit: TextEdit {
indels: [
@ -778,10 +778,10 @@ mod outer { mod fo<|>o; }
file_system_edits: [
MoveFile {
src: FileId(
2,
1,
),
anchor: FileId(
2,
1,
),
dst: "bar.rs",
},
@ -834,7 +834,7 @@ pub mod foo<|>;
source_file_edits: [
SourceFileEdit {
file_id: FileId(
2,
1,
),
edit: TextEdit {
indels: [
@ -847,7 +847,7 @@ pub mod foo<|>;
},
SourceFileEdit {
file_id: FileId(
1,
0,
),
edit: TextEdit {
indels: [
@ -862,10 +862,10 @@ pub mod foo<|>;
file_system_edits: [
MoveFile {
src: FileId(
3,
2,
),
anchor: FileId(
3,
2,
),
dst: "foo2.rs",
},

View file

@ -292,7 +292,7 @@ fn has_test_function_or_multiple_test_submodules(module: &ast::Module) -> bool {
mod tests {
use expect_test::{expect, Expect};
use crate::mock_analysis::analysis_and_position;
use crate::fixture;
use super::{RunnableAction, BENCH, BIN, DOCTEST, TEST};
@ -302,7 +302,7 @@ mod tests {
actions: &[&RunnableAction],
expect: Expect,
) {
let (analysis, position) = analysis_and_position(ra_fixture);
let (analysis, position) = fixture::position(ra_fixture);
let runnables = analysis.runnables(position.file_id).unwrap();
expect.assert_debug_eq(&runnables);
assert_eq!(
@ -335,7 +335,7 @@ fn bench() {}
Runnable {
nav: NavigationTarget {
file_id: FileId(
1,
0,
),
full_range: 1..13,
focus_range: Some(
@ -353,7 +353,7 @@ fn bench() {}
Runnable {
nav: NavigationTarget {
file_id: FileId(
1,
0,
),
full_range: 15..39,
focus_range: Some(
@ -378,7 +378,7 @@ fn bench() {}
Runnable {
nav: NavigationTarget {
file_id: FileId(
1,
0,
),
full_range: 41..75,
focus_range: Some(
@ -403,7 +403,7 @@ fn bench() {}
Runnable {
nav: NavigationTarget {
file_id: FileId(
1,
0,
),
full_range: 77..99,
focus_range: Some(
@ -494,7 +494,7 @@ fn should_have_no_runnable_6() {}
Runnable {
nav: NavigationTarget {
file_id: FileId(
1,
0,
),
full_range: 1..13,
focus_range: Some(
@ -512,7 +512,7 @@ fn should_have_no_runnable_6() {}
Runnable {
nav: NavigationTarget {
file_id: FileId(
1,
0,
),
full_range: 15..74,
focus_range: None,
@ -532,7 +532,7 @@ fn should_have_no_runnable_6() {}
Runnable {
nav: NavigationTarget {
file_id: FileId(
1,
0,
),
full_range: 76..148,
focus_range: None,
@ -552,7 +552,7 @@ fn should_have_no_runnable_6() {}
Runnable {
nav: NavigationTarget {
file_id: FileId(
1,
0,
),
full_range: 150..254,
focus_range: None,
@ -596,7 +596,7 @@ impl Data {
Runnable {
nav: NavigationTarget {
file_id: FileId(
1,
0,
),
full_range: 1..13,
focus_range: Some(
@ -614,7 +614,7 @@ impl Data {
Runnable {
nav: NavigationTarget {
file_id: FileId(
1,
0,
),
full_range: 44..98,
focus_range: None,
@ -653,7 +653,7 @@ mod test_mod {
Runnable {
nav: NavigationTarget {
file_id: FileId(
1,
0,
),
full_range: 1..51,
focus_range: Some(
@ -673,7 +673,7 @@ mod test_mod {
Runnable {
nav: NavigationTarget {
file_id: FileId(
1,
0,
),
full_range: 20..49,
focus_range: Some(
@ -733,7 +733,7 @@ mod root_tests {
Runnable {
nav: NavigationTarget {
file_id: FileId(
1,
0,
),
full_range: 22..323,
focus_range: Some(
@ -753,7 +753,7 @@ mod root_tests {
Runnable {
nav: NavigationTarget {
file_id: FileId(
1,
0,
),
full_range: 51..192,
focus_range: Some(
@ -773,7 +773,7 @@ mod root_tests {
Runnable {
nav: NavigationTarget {
file_id: FileId(
1,
0,
),
full_range: 84..126,
focus_range: Some(
@ -798,7 +798,7 @@ mod root_tests {
Runnable {
nav: NavigationTarget {
file_id: FileId(
1,
0,
),
full_range: 140..182,
focus_range: Some(
@ -823,7 +823,7 @@ mod root_tests {
Runnable {
nav: NavigationTarget {
file_id: FileId(
1,
0,
),
full_range: 202..286,
focus_range: Some(
@ -843,7 +843,7 @@ mod root_tests {
Runnable {
nav: NavigationTarget {
file_id: FileId(
1,
0,
),
full_range: 235..276,
focus_range: Some(
@ -886,7 +886,7 @@ fn test_foo1() {}
Runnable {
nav: NavigationTarget {
file_id: FileId(
1,
0,
),
full_range: 1..50,
focus_range: Some(
@ -934,7 +934,7 @@ fn test_foo1() {}
Runnable {
nav: NavigationTarget {
file_id: FileId(
1,
0,
),
full_range: 1..72,
focus_range: Some(

View file

@ -3,7 +3,7 @@ use std::fs;
use expect_test::{expect_file, ExpectFile};
use test_utils::project_dir;
use crate::{mock_analysis::single_file, FileRange, TextRange};
use crate::{fixture, FileRange, TextRange};
#[test]
fn test_highlighting() {
@ -178,7 +178,7 @@ fn accidentally_quadratic() {
let file = project_dir().join("crates/syntax/test_data/accidentally_quadratic");
let src = fs::read_to_string(file).unwrap();
let (analysis, file_id) = single_file(&src);
let (analysis, file_id) = fixture::file(&src);
// let t = std::time::Instant::now();
let _ = analysis.highlight(file_id).unwrap();
@ -187,7 +187,7 @@ fn accidentally_quadratic() {
#[test]
fn test_ranges() {
let (analysis, file_id) = single_file(
let (analysis, file_id) = fixture::file(
r#"
#[derive(Clone, Debug)]
struct Foo {
@ -228,7 +228,7 @@ fn main() {
#[test]
fn ranges_sorted() {
let (analysis, file_id) = single_file(
let (analysis, file_id) = fixture::file(
r#"
#[foo(bar = "bar")]
macro_rules! test {}
@ -462,12 +462,12 @@ macro_rules! noop {
fn test_extern_crate() {
check_highlighting(
r#"
//- /main.rs
//- /main.rs crate:main deps:std,alloc
extern crate std;
extern crate alloc as abc;
//- /std/lib.rs
//- /std/lib.rs crate:std
pub struct S;
//- /alloc/lib.rs
//- /alloc/lib.rs crate:alloc
pub struct A
"#,
expect_file!["./test_data/highlight_extern_crate.html"],
@ -479,7 +479,7 @@ fn test_extern_crate() {
/// result as HTML, and compares it with the HTML file given as `snapshot`.
/// Note that the `snapshot` file is overwritten by the rendered HTML.
fn check_highlighting(ra_fixture: &str, expect: ExpectFile, rainbow: bool) {
let (analysis, file_id) = single_file(ra_fixture);
let (analysis, file_id) = fixture::file(ra_fixture);
let actual_html = &analysis.highlight_as_html(file_id, rainbow).unwrap();
expect.assert_eq(actual_html)
}

View file

@ -104,12 +104,12 @@ fn syntax_tree_for_token(node: &SyntaxToken, text_range: TextRange) -> Option<St
mod tests {
use test_utils::assert_eq_text;
use crate::mock_analysis::{analysis_and_range, single_file};
use crate::fixture;
#[test]
fn test_syntax_tree_without_range() {
// Basic syntax
let (analysis, file_id) = single_file(r#"fn foo() {}"#);
let (analysis, file_id) = fixture::file(r#"fn foo() {}"#);
let syn = analysis.syntax_tree(file_id, None).unwrap();
assert_eq_text!(
@ -132,7 +132,7 @@ SOURCE_FILE@0..11
.trim()
);
let (analysis, file_id) = single_file(
let (analysis, file_id) = fixture::file(
r#"
fn test() {
assert!("
@ -184,7 +184,7 @@ SOURCE_FILE@0..60
#[test]
fn test_syntax_tree_with_range() {
let (analysis, range) = analysis_and_range(r#"<|>fn foo() {}<|>"#.trim());
let (analysis, range) = fixture::range(r#"<|>fn foo() {}<|>"#.trim());
let syn = analysis.syntax_tree(range.file_id, Some(range.range)).unwrap();
assert_eq_text!(
@ -206,7 +206,7 @@ FN@0..11
.trim()
);
let (analysis, range) = analysis_and_range(
let (analysis, range) = fixture::range(
r#"fn test() {
<|>assert!("
fn foo() {
@ -242,7 +242,7 @@ EXPR_STMT@16..58
#[test]
fn test_syntax_tree_inside_string() {
let (analysis, range) = analysis_and_range(
let (analysis, range) = fixture::range(
r#"fn test() {
assert!("
<|>fn foo() {
@ -276,7 +276,7 @@ SOURCE_FILE@0..12
);
// With a raw string
let (analysis, range) = analysis_and_range(
let (analysis, range) = fixture::range(
r###"fn test() {
assert!(r#"
<|>fn foo() {
@ -310,7 +310,7 @@ SOURCE_FILE@0..12
);
// With a raw string
let (analysis, range) = analysis_and_range(
let (analysis, range) = fixture::range(
r###"fn test() {
assert!(r<|>#"
fn foo() {

View file

@ -109,10 +109,10 @@ mod tests {
use stdx::trim_indent;
use test_utils::{assert_eq_text, mark};
use crate::mock_analysis::analysis_and_position;
use crate::fixture;
fn apply_on_enter(before: &str) -> Option<String> {
let (analysis, position) = analysis_and_position(&before);
let (analysis, position) = fixture::position(&before);
let result = analysis.on_enter(position).unwrap()?;
let mut actual = analysis.file_text(position.file_id).unwrap().to_string();

View file

@ -1,58 +1,16 @@
//! Defines a unit of change that can applied to a state of IDE to get the next
//! state. Changes are transactional.
//! Applies changes to the IDE state transactionally.
use std::{fmt, sync::Arc};
use base_db::{
salsa::{Database, Durability, SweepStrategy},
CrateGraph, FileId, SourceDatabase, SourceDatabaseExt, SourceRoot, SourceRootId,
Change, FileId, SourceRootId,
};
use profile::{memory_usage, Bytes};
use rustc_hash::FxHashSet;
use crate::{symbol_index::SymbolsDatabase, RootDatabase};
#[derive(Default)]
pub struct AnalysisChange {
roots: Option<Vec<SourceRoot>>,
files_changed: Vec<(FileId, Option<Arc<String>>)>,
crate_graph: Option<CrateGraph>,
}
impl fmt::Debug for AnalysisChange {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
let mut d = fmt.debug_struct("AnalysisChange");
if let Some(roots) = &self.roots {
d.field("roots", roots);
}
if !self.files_changed.is_empty() {
d.field("files_changed", &self.files_changed.len());
}
if self.crate_graph.is_some() {
d.field("crate_graph", &self.crate_graph);
}
d.finish()
}
}
impl AnalysisChange {
pub fn new() -> AnalysisChange {
AnalysisChange::default()
}
pub fn set_roots(&mut self, roots: Vec<SourceRoot>) {
self.roots = Some(roots);
}
pub fn change_file(&mut self, file_id: FileId, new_text: Option<Arc<String>>) {
self.files_changed.push((file_id, new_text))
}
pub fn set_crate_graph(&mut self, graph: CrateGraph) {
self.crate_graph = Some(graph);
}
}
#[derive(Debug)]
struct AddFile {
file_id: FileId,
@ -87,41 +45,25 @@ impl RootDatabase {
self.salsa_runtime_mut().synthetic_write(Durability::LOW);
}
pub fn apply_change(&mut self, change: AnalysisChange) {
pub fn apply_change(&mut self, change: Change) {
let _p = profile::span("RootDatabase::apply_change");
self.request_cancellation();
log::info!("apply_change {:?}", change);
if let Some(roots) = change.roots {
if let Some(roots) = &change.roots {
let mut local_roots = FxHashSet::default();
let mut library_roots = FxHashSet::default();
for (idx, root) in roots.into_iter().enumerate() {
for (idx, root) in roots.iter().enumerate() {
let root_id = SourceRootId(idx as u32);
let durability = durability(&root);
if root.is_library {
library_roots.insert(root_id);
} else {
local_roots.insert(root_id);
}
for file_id in root.iter() {
self.set_file_source_root_with_durability(file_id, root_id, durability);
}
self.set_source_root_with_durability(root_id, Arc::new(root), durability);
}
self.set_local_roots_with_durability(Arc::new(local_roots), Durability::HIGH);
self.set_library_roots_with_durability(Arc::new(library_roots), Durability::HIGH);
}
for (file_id, text) in change.files_changed {
let source_root_id = self.file_source_root(file_id);
let source_root = self.source_root(source_root_id);
let durability = durability(&source_root);
// XXX: can't actually remove the file, just reset the text
let text = text.unwrap_or_default();
self.set_file_text_with_durability(file_id, text, durability)
}
if let Some(crate_graph) = change.crate_graph {
self.set_crate_graph_with_durability(Arc::new(crate_graph), Durability::HIGH)
}
change.apply(self);
}
pub fn collect_garbage(&mut self) {
@ -295,11 +237,3 @@ impl RootDatabase {
acc
}
}
fn durability(source_root: &SourceRoot) -> Durability {
if source_root.is_library {
Durability::HIGH
} else {
Durability::LOW
}
}

View file

@ -2,10 +2,10 @@
//!
//! It is mainly a `HirDatabase` for semantic analysis, plus a `SymbolsDatabase`, for fuzzy search.
mod apply_change;
pub mod label;
pub mod line_index;
pub mod symbol_index;
pub mod change;
pub mod defs;
pub mod search;
pub mod imports_locator;

View file

@ -8,8 +8,7 @@ use base_db::{
FileId,
};
use ide::{
Analysis, AnalysisChange, AnalysisHost, CompletionConfig, DiagnosticsConfig, FilePosition,
LineCol,
Analysis, AnalysisHost, Change, CompletionConfig, DiagnosticsConfig, FilePosition, LineCol,
};
use vfs::AbsPathBuf;
@ -143,7 +142,7 @@ fn do_work<F: Fn(&Analysis) -> T, T>(host: &mut AnalysisHost, file_id: FileId, w
{
let mut text = host.analysis().file_text(file_id).unwrap().to_string();
text.push_str("\n/* Hello world */\n");
let mut change = AnalysisChange::new();
let mut change = Change::new();
change.change_file(file_id, Some(Arc::new(text)));
host.apply_change(change);
}
@ -156,7 +155,7 @@ fn do_work<F: Fn(&Analysis) -> T, T>(host: &mut AnalysisHost, file_id: FileId, w
{
let mut text = host.analysis().file_text(file_id).unwrap().to_string();
text.push_str("\npub fn _dummy() {}\n");
let mut change = AnalysisChange::new();
let mut change = Change::new();
change.change_file(file_id, Some(Arc::new(text)));
host.apply_change(change);
}

View file

@ -5,7 +5,7 @@ use std::{path::Path, sync::Arc};
use anyhow::Result;
use base_db::CrateGraph;
use crossbeam_channel::{unbounded, Receiver};
use ide::{AnalysisChange, AnalysisHost};
use ide::{AnalysisHost, Change};
use project_model::{CargoConfig, ProcMacroClient, ProjectManifest, ProjectWorkspace};
use vfs::{loader::Handle, AbsPath, AbsPathBuf};
@ -62,7 +62,7 @@ fn load(
) -> AnalysisHost {
let lru_cap = std::env::var("RA_LRU_CAP").ok().and_then(|it| it.parse::<usize>().ok());
let mut host = AnalysisHost::new(lru_cap);
let mut analysis_change = AnalysisChange::new();
let mut analysis_change = Change::new();
// wait until Vfs has loaded all roots
for task in receiver {

View file

@ -8,7 +8,7 @@ use std::{sync::Arc, time::Instant};
use base_db::{CrateId, VfsPath};
use crossbeam_channel::{unbounded, Receiver, Sender};
use flycheck::FlycheckHandle;
use ide::{Analysis, AnalysisChange, AnalysisHost, FileId};
use ide::{Analysis, AnalysisHost, Change, FileId};
use lsp_types::{SemanticTokens, Url};
use parking_lot::{Mutex, RwLock};
use project_model::{CargoWorkspace, ProcMacroClient, ProjectWorkspace, Target};
@ -139,7 +139,7 @@ impl GlobalState {
let mut has_fs_changes = false;
let change = {
let mut change = AnalysisChange::new();
let mut change = Change::new();
let (vfs, line_endings_map) = &mut *self.vfs.write();
let changed_files = vfs.take_changes();
if changed_files.is_empty() {

View file

@ -3,7 +3,7 @@ use std::{mem, sync::Arc};
use base_db::{CrateGraph, SourceRoot, VfsPath};
use flycheck::{FlycheckConfig, FlycheckHandle};
use ide::AnalysisChange;
use ide::Change;
use project_model::{ProcMacroClient, ProjectWorkspace};
use vfs::{file_set::FileSetConfig, AbsPath, AbsPathBuf, ChangeKind};
@ -171,7 +171,7 @@ impl GlobalState {
);
}
let mut change = AnalysisChange::new();
let mut change = Change::new();
let project_folders = ProjectFolders::new(&workspaces);