diff options
author | Seivan Heidari <[email protected]> | 2019-11-04 12:45:27 +0000 |
---|---|---|
committer | Seivan Heidari <[email protected]> | 2019-11-04 12:45:27 +0000 |
commit | dad9bc6caad71e6aebb92ad9883c08d30431e9b1 (patch) | |
tree | 6495d47108bc56ab0fbb358125fe65ebece8934f /crates/ra_db/src | |
parent | 1d8bb4c6c1fef1f8ea513e07d0a7d4c5483129d2 (diff) | |
parent | cc2d75d0f88bdcb1b3e20db36decb6ee6eca517a (diff) |
Merge branch 'master' into feature/themes
Diffstat (limited to 'crates/ra_db/src')
-rw-r--r-- | crates/ra_db/src/fixture.rs | 186 | ||||
-rw-r--r-- | crates/ra_db/src/input.rs | 4 | ||||
-rw-r--r-- | crates/ra_db/src/lib.rs | 3 |
3 files changed, 191 insertions, 2 deletions
diff --git a/crates/ra_db/src/fixture.rs b/crates/ra_db/src/fixture.rs new file mode 100644 index 000000000..f5dd59f84 --- /dev/null +++ b/crates/ra_db/src/fixture.rs | |||
@@ -0,0 +1,186 @@ | |||
1 | //! FIXME: write short doc here | ||
2 | |||
3 | use std::sync::Arc; | ||
4 | |||
5 | use ra_cfg::CfgOptions; | ||
6 | use rustc_hash::FxHashMap; | ||
7 | use test_utils::{extract_offset, parse_fixture, CURSOR_MARKER}; | ||
8 | |||
9 | use crate::{ | ||
10 | CrateGraph, Edition, FileId, FilePosition, RelativePathBuf, SourceDatabaseExt, SourceRoot, | ||
11 | SourceRootId, | ||
12 | }; | ||
13 | |||
14 | pub const WORKSPACE: SourceRootId = SourceRootId(0); | ||
15 | |||
16 | pub trait WithFixture: Default + SourceDatabaseExt + 'static { | ||
17 | fn with_single_file(text: &str) -> (Self, FileId) { | ||
18 | let mut db = Self::default(); | ||
19 | let file_id = with_single_file(&mut db, text); | ||
20 | (db, file_id) | ||
21 | } | ||
22 | |||
23 | fn with_files(fixture: &str) -> Self { | ||
24 | let mut db = Self::default(); | ||
25 | let pos = with_files(&mut db, fixture); | ||
26 | assert!(pos.is_none()); | ||
27 | db | ||
28 | } | ||
29 | |||
30 | fn with_position(fixture: &str) -> (Self, FilePosition) { | ||
31 | let mut db = Self::default(); | ||
32 | let pos = with_files(&mut db, fixture); | ||
33 | (db, pos.unwrap()) | ||
34 | } | ||
35 | } | ||
36 | |||
37 | impl<DB: SourceDatabaseExt + Default + 'static> WithFixture for DB {} | ||
38 | |||
39 | fn with_single_file(db: &mut dyn SourceDatabaseExt, text: &str) -> FileId { | ||
40 | let file_id = FileId(0); | ||
41 | let rel_path: RelativePathBuf = "/main.rs".into(); | ||
42 | |||
43 | let mut source_root = SourceRoot::default(); | ||
44 | source_root.insert_file(rel_path.clone(), file_id); | ||
45 | |||
46 | let mut crate_graph = CrateGraph::default(); | ||
47 | crate_graph.add_crate_root(file_id, Edition::Edition2018, CfgOptions::default()); | ||
48 | |||
49 | db.set_file_text(file_id, Arc::new(text.to_string())); | ||
50 | db.set_file_relative_path(file_id, rel_path); | ||
51 | db.set_file_source_root(file_id, WORKSPACE); | ||
52 | db.set_source_root(WORKSPACE, Arc::new(source_root)); | ||
53 | db.set_crate_graph(Arc::new(crate_graph)); | ||
54 | |||
55 | file_id | ||
56 | } | ||
57 | |||
58 | fn with_files(db: &mut dyn SourceDatabaseExt, fixture: &str) -> Option<FilePosition> { | ||
59 | let fixture = parse_fixture(fixture); | ||
60 | |||
61 | let mut crate_graph = CrateGraph::default(); | ||
62 | let mut crates = FxHashMap::default(); | ||
63 | let mut crate_deps = Vec::new(); | ||
64 | let mut default_crate_root: Option<FileId> = None; | ||
65 | |||
66 | let mut source_root = SourceRoot::default(); | ||
67 | let mut source_root_id = WORKSPACE; | ||
68 | let mut source_root_prefix: RelativePathBuf = "/".into(); | ||
69 | let mut file_id = FileId(0); | ||
70 | |||
71 | let mut file_position = None; | ||
72 | |||
73 | for entry in fixture.iter() { | ||
74 | let meta = match parse_meta(&entry.meta) { | ||
75 | ParsedMeta::Root { path } => { | ||
76 | let source_root = std::mem::replace(&mut source_root, SourceRoot::default()); | ||
77 | db.set_source_root(source_root_id, Arc::new(source_root)); | ||
78 | source_root_id.0 += 1; | ||
79 | source_root_prefix = path; | ||
80 | continue; | ||
81 | } | ||
82 | ParsedMeta::File(it) => it, | ||
83 | }; | ||
84 | assert!(meta.path.starts_with(&source_root_prefix)); | ||
85 | |||
86 | if let Some(krate) = meta.krate { | ||
87 | let crate_id = crate_graph.add_crate_root(file_id, meta.edition, meta.cfg); | ||
88 | let prev = crates.insert(krate.clone(), crate_id); | ||
89 | assert!(prev.is_none()); | ||
90 | for dep in meta.deps { | ||
91 | crate_deps.push((krate.clone(), dep)) | ||
92 | } | ||
93 | } else if meta.path == "/main.rs" || meta.path == "/lib.rs" { | ||
94 | assert!(default_crate_root.is_none()); | ||
95 | default_crate_root = Some(file_id); | ||
96 | } | ||
97 | |||
98 | let text = if entry.text.contains(CURSOR_MARKER) { | ||
99 | let (offset, text) = extract_offset(&entry.text); | ||
100 | assert!(file_position.is_none()); | ||
101 | file_position = Some(FilePosition { file_id, offset }); | ||
102 | text.to_string() | ||
103 | } else { | ||
104 | entry.text.to_string() | ||
105 | }; | ||
106 | |||
107 | db.set_file_text(file_id, Arc::new(text)); | ||
108 | db.set_file_relative_path(file_id, meta.path.clone()); | ||
109 | db.set_file_source_root(file_id, source_root_id); | ||
110 | source_root.insert_file(meta.path, file_id); | ||
111 | |||
112 | file_id.0 += 1; | ||
113 | } | ||
114 | |||
115 | if crates.is_empty() { | ||
116 | let crate_root = default_crate_root.unwrap(); | ||
117 | crate_graph.add_crate_root(crate_root, Edition::Edition2018, CfgOptions::default()); | ||
118 | } else { | ||
119 | for (from, to) in crate_deps { | ||
120 | let from_id = crates[&from]; | ||
121 | let to_id = crates[&to]; | ||
122 | crate_graph.add_dep(from_id, to.into(), to_id).unwrap(); | ||
123 | } | ||
124 | } | ||
125 | |||
126 | db.set_source_root(source_root_id, Arc::new(source_root)); | ||
127 | db.set_crate_graph(Arc::new(crate_graph)); | ||
128 | |||
129 | file_position | ||
130 | } | ||
131 | |||
132 | enum ParsedMeta { | ||
133 | Root { path: RelativePathBuf }, | ||
134 | File(FileMeta), | ||
135 | } | ||
136 | |||
137 | struct FileMeta { | ||
138 | path: RelativePathBuf, | ||
139 | krate: Option<String>, | ||
140 | deps: Vec<String>, | ||
141 | cfg: CfgOptions, | ||
142 | edition: Edition, | ||
143 | } | ||
144 | |||
145 | //- /lib.rs crate:foo deps:bar,baz | ||
146 | fn parse_meta(meta: &str) -> ParsedMeta { | ||
147 | let components = meta.split_ascii_whitespace().collect::<Vec<_>>(); | ||
148 | |||
149 | if components[0] == "root" { | ||
150 | let path: RelativePathBuf = components[1].into(); | ||
151 | assert!(path.starts_with("/") && path.ends_with("/")); | ||
152 | return ParsedMeta::Root { path }; | ||
153 | } | ||
154 | |||
155 | let path: RelativePathBuf = components[0].into(); | ||
156 | assert!(path.starts_with("/")); | ||
157 | |||
158 | let mut krate = None; | ||
159 | let mut deps = Vec::new(); | ||
160 | let mut edition = Edition::Edition2018; | ||
161 | let mut cfg = CfgOptions::default(); | ||
162 | for component in components[1..].iter() { | ||
163 | let (key, value) = split1(component, ':').unwrap(); | ||
164 | match key { | ||
165 | "crate" => krate = Some(value.to_string()), | ||
166 | "deps" => deps = value.split(',').map(|it| it.to_string()).collect(), | ||
167 | "edition" => edition = Edition::from_string(&value), | ||
168 | "cfg" => { | ||
169 | for key in value.split(',') { | ||
170 | match split1(key, '=') { | ||
171 | None => cfg.insert_atom(key.into()), | ||
172 | Some((k, v)) => cfg.insert_key_value(k.into(), v.into()), | ||
173 | } | ||
174 | } | ||
175 | } | ||
176 | _ => panic!("bad component: {:?}", component), | ||
177 | } | ||
178 | } | ||
179 | |||
180 | ParsedMeta::File(FileMeta { path, krate, deps, edition, cfg }) | ||
181 | } | ||
182 | |||
183 | fn split1(haystack: &str, delim: char) -> Option<(&str, &str)> { | ||
184 | let idx = haystack.find(delim)?; | ||
185 | Some((&haystack[..idx], &haystack[idx + delim.len_utf8()..])) | ||
186 | } | ||
diff --git a/crates/ra_db/src/input.rs b/crates/ra_db/src/input.rs index eafa95921..60f7dc881 100644 --- a/crates/ra_db/src/input.rs +++ b/crates/ra_db/src/input.rs | |||
@@ -6,13 +6,14 @@ | |||
6 | //! actual IO. See `vfs` and `project_model` in the `ra_lsp_server` crate for how | 6 | //! actual IO. See `vfs` and `project_model` in the `ra_lsp_server` crate for how |
7 | //! actual IO is done and lowered to input. | 7 | //! actual IO is done and lowered to input. |
8 | 8 | ||
9 | use relative_path::{RelativePath, RelativePathBuf}; | ||
10 | use rustc_hash::FxHashMap; | 9 | use rustc_hash::FxHashMap; |
11 | 10 | ||
12 | use ra_cfg::CfgOptions; | 11 | use ra_cfg::CfgOptions; |
13 | use ra_syntax::SmolStr; | 12 | use ra_syntax::SmolStr; |
14 | use rustc_hash::FxHashSet; | 13 | use rustc_hash::FxHashSet; |
15 | 14 | ||
15 | use crate::{RelativePath, RelativePathBuf}; | ||
16 | |||
16 | /// `FileId` is an integer which uniquely identifies a file. File paths are | 17 | /// `FileId` is an integer which uniquely identifies a file. File paths are |
17 | /// messy and system-dependent, so most of the code should work directly with | 18 | /// messy and system-dependent, so most of the code should work directly with |
18 | /// `FileId`, without inspecting the path. The mapping between `FileId` and path | 19 | /// `FileId`, without inspecting the path. The mapping between `FileId` and path |
@@ -97,6 +98,7 @@ pub enum Edition { | |||
97 | } | 98 | } |
98 | 99 | ||
99 | impl Edition { | 100 | impl Edition { |
101 | //FIXME: replace with FromStr with proper error handling | ||
100 | pub fn from_string(s: &str) -> Edition { | 102 | pub fn from_string(s: &str) -> Edition { |
101 | match s { | 103 | match s { |
102 | "2015" => Edition::Edition2015, | 104 | "2015" => Edition::Edition2015, |
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 @@ | |||
1 | //! ra_db defines basic database traits. The concrete DB is defined by ra_ide_api. | 1 | //! ra_db defines basic database traits. The concrete DB is defined by ra_ide_api. |
2 | mod cancellation; | 2 | mod cancellation; |
3 | mod input; | 3 | mod input; |
4 | pub mod fixture; | ||
4 | 5 | ||
5 | use std::{panic, sync::Arc}; | 6 | use std::{panic, sync::Arc}; |
6 | 7 | ||
7 | use ra_prof::profile; | 8 | use ra_prof::profile; |
8 | use ra_syntax::{ast, Parse, SourceFile, TextRange, TextUnit}; | 9 | use ra_syntax::{ast, Parse, SourceFile, TextRange, TextUnit}; |
9 | use relative_path::{RelativePath, RelativePathBuf}; | ||
10 | 10 | ||
11 | pub use crate::{ | 11 | pub use crate::{ |
12 | cancellation::Canceled, | 12 | cancellation::Canceled, |
13 | input::{CrateGraph, CrateId, Dependency, Edition, FileId, SourceRoot, SourceRootId}, | 13 | input::{CrateGraph, CrateId, Dependency, Edition, FileId, SourceRoot, SourceRootId}, |
14 | }; | 14 | }; |
15 | pub use relative_path::{RelativePath, RelativePathBuf}; | ||
15 | pub use salsa; | 16 | pub use salsa; |
16 | 17 | ||
17 | pub trait CheckCanceled { | 18 | pub trait CheckCanceled { |