From 0933d914a37c4ab57fda6fe95464d194dab6f80c Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Sun, 3 Nov 2019 20:53:17 +0300 Subject: Introduce ra_db::fixture fixture module The goal here is to share more testing infrastructure between crates. --- crates/ra_db/Cargo.toml | 1 + crates/ra_db/src/fixture.rs | 40 ++++++++++++++++++++++++++++++++++++++++ crates/ra_db/src/lib.rs | 3 ++- 3 files changed, 43 insertions(+), 1 deletion(-) create mode 100644 crates/ra_db/src/fixture.rs (limited to 'crates/ra_db') diff --git a/crates/ra_db/Cargo.toml b/crates/ra_db/Cargo.toml index 3394ae8ce..bf1f7920c 100644 --- a/crates/ra_db/Cargo.toml +++ b/crates/ra_db/Cargo.toml @@ -12,3 +12,4 @@ rustc-hash = "1.0" ra_syntax = { path = "../ra_syntax" } ra_cfg = { path = "../ra_cfg" } ra_prof = { path = "../ra_prof" } +test_utils = { path = "../test_utils" } diff --git a/crates/ra_db/src/fixture.rs b/crates/ra_db/src/fixture.rs new file mode 100644 index 000000000..469251fe9 --- /dev/null +++ b/crates/ra_db/src/fixture.rs @@ -0,0 +1,40 @@ +//! FIXME: write short doc here + +use std::sync::Arc; + +use ra_cfg::CfgOptions; + +use crate::{ + CrateGraph, Edition, FileId, RelativePathBuf, SourceDatabaseExt, SourceRoot, SourceRootId, +}; + +pub const WORKSPACE: SourceRootId = SourceRootId(0); + +pub trait WithFixture: Default + SourceDatabaseExt + 'static { + fn with_single_file(text: &str) -> (Self, FileId) { + let mut db = Self::default(); + let file_id = with_single_file(&mut db, text); + (db, file_id) + } +} + +impl WithFixture for DB {} + +fn with_single_file(db: &mut dyn SourceDatabaseExt, text: &str) -> FileId { + let file_id = FileId(0); + let rel_path: RelativePathBuf = "/main.rs".into(); + + let mut source_root = SourceRoot::default(); + source_root.insert_file(rel_path.clone(), file_id); + + let mut crate_graph = CrateGraph::default(); + crate_graph.add_crate_root(file_id, Edition::Edition2018, CfgOptions::default()); + + db.set_file_text(file_id, Arc::new(text.to_string())); + db.set_file_relative_path(file_id, rel_path); + db.set_file_source_root(file_id, WORKSPACE); + db.set_source_root(WORKSPACE, Arc::new(source_root)); + db.set_crate_graph(Arc::new(crate_graph)); + + file_id +} diff --git a/crates/ra_db/src/lib.rs b/crates/ra_db/src/lib.rs index 0d1ab4843..b6bfd531d 100644 --- a/crates/ra_db/src/lib.rs +++ b/crates/ra_db/src/lib.rs @@ -1,17 +1,18 @@ //! ra_db defines basic database traits. The concrete DB is defined by ra_ide_api. mod cancellation; mod input; +pub mod fixture; use std::{panic, sync::Arc}; use ra_prof::profile; use ra_syntax::{ast, Parse, SourceFile, TextRange, TextUnit}; -use relative_path::{RelativePath, RelativePathBuf}; pub use crate::{ cancellation::Canceled, input::{CrateGraph, CrateId, Dependency, Edition, FileId, SourceRoot, SourceRootId}, }; +pub use relative_path::{RelativePath, RelativePathBuf}; pub use salsa; pub trait CheckCanceled { -- cgit v1.2.3 From 6fba51c5fc05264abcbf971dcf28142746588d74 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Sun, 3 Nov 2019 23:35:48 +0300 Subject: move crate_def_map tests to hir_def --- crates/ra_db/src/fixture.rs | 148 +++++++++++++++++++++++++++++++++++++++++++- crates/ra_db/src/input.rs | 1 + 2 files changed, 148 insertions(+), 1 deletion(-) (limited to 'crates/ra_db') diff --git a/crates/ra_db/src/fixture.rs b/crates/ra_db/src/fixture.rs index 469251fe9..f5dd59f84 100644 --- a/crates/ra_db/src/fixture.rs +++ b/crates/ra_db/src/fixture.rs @@ -3,9 +3,12 @@ use std::sync::Arc; use ra_cfg::CfgOptions; +use rustc_hash::FxHashMap; +use test_utils::{extract_offset, parse_fixture, CURSOR_MARKER}; use crate::{ - CrateGraph, Edition, FileId, RelativePathBuf, SourceDatabaseExt, SourceRoot, SourceRootId, + CrateGraph, Edition, FileId, FilePosition, RelativePathBuf, SourceDatabaseExt, SourceRoot, + SourceRootId, }; pub const WORKSPACE: SourceRootId = SourceRootId(0); @@ -16,6 +19,19 @@ pub trait WithFixture: Default + SourceDatabaseExt + 'static { let file_id = with_single_file(&mut db, text); (db, file_id) } + + fn with_files(fixture: &str) -> Self { + let mut db = Self::default(); + let pos = with_files(&mut db, fixture); + assert!(pos.is_none()); + db + } + + fn with_position(fixture: &str) -> (Self, FilePosition) { + let mut db = Self::default(); + let pos = with_files(&mut db, fixture); + (db, pos.unwrap()) + } } impl WithFixture for DB {} @@ -38,3 +54,133 @@ fn with_single_file(db: &mut dyn SourceDatabaseExt, text: &str) -> FileId { file_id } + +fn with_files(db: &mut dyn SourceDatabaseExt, fixture: &str) -> Option { + let fixture = parse_fixture(fixture); + + let mut crate_graph = CrateGraph::default(); + let mut crates = FxHashMap::default(); + let mut crate_deps = Vec::new(); + let mut default_crate_root: Option = None; + + let mut source_root = SourceRoot::default(); + let mut source_root_id = WORKSPACE; + let mut source_root_prefix: RelativePathBuf = "/".into(); + let mut file_id = FileId(0); + + let mut file_position = None; + + for entry in fixture.iter() { + let meta = match parse_meta(&entry.meta) { + ParsedMeta::Root { path } => { + let source_root = std::mem::replace(&mut source_root, SourceRoot::default()); + db.set_source_root(source_root_id, Arc::new(source_root)); + source_root_id.0 += 1; + source_root_prefix = path; + continue; + } + ParsedMeta::File(it) => it, + }; + 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, meta.cfg); + let prev = crates.insert(krate.clone(), crate_id); + assert!(prev.is_none()); + for dep in meta.deps { + crate_deps.push((krate.clone(), dep)) + } + } else if meta.path == "/main.rs" || meta.path == "/lib.rs" { + assert!(default_crate_root.is_none()); + default_crate_root = Some(file_id); + } + + let text = if entry.text.contains(CURSOR_MARKER) { + let (offset, text) = extract_offset(&entry.text); + assert!(file_position.is_none()); + file_position = Some(FilePosition { file_id, offset }); + text.to_string() + } else { + entry.text.to_string() + }; + + db.set_file_text(file_id, Arc::new(text)); + db.set_file_relative_path(file_id, meta.path.clone()); + db.set_file_source_root(file_id, source_root_id); + source_root.insert_file(meta.path, 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, CfgOptions::default()); + } else { + for (from, to) in crate_deps { + let from_id = crates[&from]; + let to_id = crates[&to]; + crate_graph.add_dep(from_id, to.into(), to_id).unwrap(); + } + } + + db.set_source_root(source_root_id, Arc::new(source_root)); + db.set_crate_graph(Arc::new(crate_graph)); + + file_position +} + +enum ParsedMeta { + Root { path: RelativePathBuf }, + File(FileMeta), +} + +struct FileMeta { + path: RelativePathBuf, + krate: Option, + deps: Vec, + cfg: CfgOptions, + edition: Edition, +} + +//- /lib.rs crate:foo deps:bar,baz +fn parse_meta(meta: &str) -> ParsedMeta { + let components = meta.split_ascii_whitespace().collect::>(); + + if components[0] == "root" { + let path: RelativePathBuf = components[1].into(); + assert!(path.starts_with("/") && path.ends_with("/")); + return ParsedMeta::Root { path }; + } + + let path: RelativePathBuf = components[0].into(); + assert!(path.starts_with("/")); + + let mut krate = None; + let mut deps = Vec::new(); + let mut edition = Edition::Edition2018; + let mut cfg = CfgOptions::default(); + for component in components[1..].iter() { + let (key, value) = split1(component, ':').unwrap(); + match key { + "crate" => krate = Some(value.to_string()), + "deps" => deps = value.split(',').map(|it| it.to_string()).collect(), + "edition" => edition = Edition::from_string(&value), + "cfg" => { + for key in value.split(',') { + match split1(key, '=') { + None => cfg.insert_atom(key.into()), + Some((k, v)) => cfg.insert_key_value(k.into(), v.into()), + } + } + } + _ => panic!("bad component: {:?}", component), + } + } + + ParsedMeta::File(FileMeta { path, krate, deps, edition, cfg }) +} + +fn split1(haystack: &str, delim: char) -> Option<(&str, &str)> { + let idx = haystack.find(delim)?; + Some((&haystack[..idx], &haystack[idx + delim.len_utf8()..])) +} diff --git a/crates/ra_db/src/input.rs b/crates/ra_db/src/input.rs index eafa95921..7c8dac1d3 100644 --- a/crates/ra_db/src/input.rs +++ b/crates/ra_db/src/input.rs @@ -97,6 +97,7 @@ pub enum Edition { } impl Edition { + //FIXME: replace with FromStr with proper error handling pub fn from_string(s: &str) -> Edition { match s { "2015" => Edition::Edition2015, -- cgit v1.2.3 From 3603d0213480c7b3423345d21243397eb904a073 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Mon, 4 Nov 2019 01:14:17 +0300 Subject: Reexport relative_path from ra_db --- crates/ra_db/src/input.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'crates/ra_db') diff --git a/crates/ra_db/src/input.rs b/crates/ra_db/src/input.rs index 7c8dac1d3..60f7dc881 100644 --- a/crates/ra_db/src/input.rs +++ b/crates/ra_db/src/input.rs @@ -6,13 +6,14 @@ //! actual IO. See `vfs` and `project_model` in the `ra_lsp_server` crate for how //! actual IO is done and lowered to input. -use relative_path::{RelativePath, RelativePathBuf}; use rustc_hash::FxHashMap; use ra_cfg::CfgOptions; use ra_syntax::SmolStr; use rustc_hash::FxHashSet; +use crate::{RelativePath, RelativePathBuf}; + /// `FileId` is an integer which uniquely identifies a file. File paths are /// messy and system-dependent, so most of the code should work directly with /// `FileId`, without inspecting the path. The mapping between `FileId` and path -- cgit v1.2.3