aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_db/src
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_db/src')
-rw-r--r--crates/ra_db/src/fixture.rs70
-rw-r--r--crates/ra_db/src/input.rs195
-rw-r--r--crates/ra_db/src/lib.rs18
3 files changed, 213 insertions, 70 deletions
diff --git a/crates/ra_db/src/fixture.rs b/crates/ra_db/src/fixture.rs
index da7af110c..3dc86ca2d 100644
--- a/crates/ra_db/src/fixture.rs
+++ b/crates/ra_db/src/fixture.rs
@@ -5,7 +5,7 @@ use std::sync::Arc;
5 5
6use ra_cfg::CfgOptions; 6use ra_cfg::CfgOptions;
7use rustc_hash::FxHashMap; 7use rustc_hash::FxHashMap;
8use test_utils::{extract_offset, parse_fixture, CURSOR_MARKER}; 8use test_utils::{extract_offset, parse_fixture, parse_single_fixture, CURSOR_MARKER};
9 9
10use crate::{ 10use crate::{
11 input::CrateName, CrateGraph, CrateId, Edition, Env, FileId, FilePosition, RelativePathBuf, 11 input::CrateName, CrateGraph, CrateId, Edition, Env, FileId, FilePosition, RelativePathBuf,
@@ -45,22 +45,45 @@ pub trait WithFixture: Default + SourceDatabaseExt + 'static {
45 45
46impl<DB: SourceDatabaseExt + Default + 'static> WithFixture for DB {} 46impl<DB: SourceDatabaseExt + Default + 'static> WithFixture for DB {}
47 47
48fn with_single_file(db: &mut dyn SourceDatabaseExt, text: &str) -> FileId { 48fn with_single_file(db: &mut dyn SourceDatabaseExt, ra_fixture: &str) -> FileId {
49 let file_id = FileId(0); 49 let file_id = FileId(0);
50 let rel_path: RelativePathBuf = "/main.rs".into(); 50 let rel_path: RelativePathBuf = "/main.rs".into();
51 51
52 let mut source_root = SourceRoot::new_local(); 52 let mut source_root = SourceRoot::new_local();
53 source_root.insert_file(rel_path.clone(), file_id); 53 source_root.insert_file(rel_path.clone(), file_id);
54 54
55 let mut crate_graph = CrateGraph::default(); 55 let fixture = parse_single_fixture(ra_fixture);
56 crate_graph.add_crate_root( 56
57 file_id, 57 let crate_graph = if let Some(entry) = fixture {
58 Edition::Edition2018, 58 let meta = match parse_meta(&entry.meta) {
59 CfgOptions::default(), 59 ParsedMeta::File(it) => it,
60 Env::default(), 60 _ => panic!("with_single_file only support file meta"),
61 ); 61 };
62 62
63 db.set_file_text(file_id, Arc::new(text.to_string())); 63 let mut crate_graph = CrateGraph::default();
64 crate_graph.add_crate_root(
65 file_id,
66 meta.edition,
67 meta.krate,
68 meta.cfg,
69 meta.env,
70 Default::default(),
71 );
72 crate_graph
73 } else {
74 let mut crate_graph = CrateGraph::default();
75 crate_graph.add_crate_root(
76 file_id,
77 Edition::Edition2018,
78 None,
79 CfgOptions::default(),
80 Env::default(),
81 Default::default(),
82 );
83 crate_graph
84 };
85
86 db.set_file_text(file_id, Arc::new(ra_fixture.to_string()));
64 db.set_file_relative_path(file_id, rel_path); 87 db.set_file_relative_path(file_id, rel_path);
65 db.set_file_source_root(file_id, WORKSPACE); 88 db.set_file_source_root(file_id, WORKSPACE);
66 db.set_source_root(WORKSPACE, Arc::new(source_root)); 89 db.set_source_root(WORKSPACE, Arc::new(source_root));
@@ -98,8 +121,14 @@ fn with_files(db: &mut dyn SourceDatabaseExt, fixture: &str) -> Option<FilePosit
98 assert!(meta.path.starts_with(&source_root_prefix)); 121 assert!(meta.path.starts_with(&source_root_prefix));
99 122
100 if let Some(krate) = meta.krate { 123 if let Some(krate) = meta.krate {
101 let crate_id = 124 let crate_id = crate_graph.add_crate_root(
102 crate_graph.add_crate_root(file_id, meta.edition, meta.cfg, Env::default()); 125 file_id,
126 meta.edition,
127 Some(krate.clone()),
128 meta.cfg,
129 meta.env,
130 Default::default(),
131 );
103 let prev = crates.insert(krate.clone(), crate_id); 132 let prev = crates.insert(krate.clone(), crate_id);
104 assert!(prev.is_none()); 133 assert!(prev.is_none());
105 for dep in meta.deps { 134 for dep in meta.deps {
@@ -132,8 +161,10 @@ fn with_files(db: &mut dyn SourceDatabaseExt, fixture: &str) -> Option<FilePosit
132 crate_graph.add_crate_root( 161 crate_graph.add_crate_root(
133 crate_root, 162 crate_root,
134 Edition::Edition2018, 163 Edition::Edition2018,
164 None,
135 CfgOptions::default(), 165 CfgOptions::default(),
136 Env::default(), 166 Env::default(),
167 Default::default(),
137 ); 168 );
138 } else { 169 } else {
139 for (from, to) in crate_deps { 170 for (from, to) in crate_deps {
@@ -160,9 +191,10 @@ struct FileMeta {
160 deps: Vec<String>, 191 deps: Vec<String>,
161 cfg: CfgOptions, 192 cfg: CfgOptions,
162 edition: Edition, 193 edition: Edition,
194 env: Env,
163} 195}
164 196
165//- /lib.rs crate:foo deps:bar,baz 197//- /lib.rs crate:foo deps:bar,baz cfg:foo=a,bar=b env:OUTDIR=path/to,OTHER=foo)
166fn parse_meta(meta: &str) -> ParsedMeta { 198fn parse_meta(meta: &str) -> ParsedMeta {
167 let components = meta.split_ascii_whitespace().collect::<Vec<_>>(); 199 let components = meta.split_ascii_whitespace().collect::<Vec<_>>();
168 200
@@ -179,6 +211,7 @@ fn parse_meta(meta: &str) -> ParsedMeta {
179 let mut deps = Vec::new(); 211 let mut deps = Vec::new();
180 let mut edition = Edition::Edition2018; 212 let mut edition = Edition::Edition2018;
181 let mut cfg = CfgOptions::default(); 213 let mut cfg = CfgOptions::default();
214 let mut env = Env::default();
182 for component in components[1..].iter() { 215 for component in components[1..].iter() {
183 let (key, value) = split1(component, ':').unwrap(); 216 let (key, value) = split1(component, ':').unwrap();
184 match key { 217 match key {
@@ -193,11 +226,18 @@ fn parse_meta(meta: &str) -> ParsedMeta {
193 } 226 }
194 } 227 }
195 } 228 }
229 "env" => {
230 for key in value.split(',') {
231 if let Some((k, v)) = split1(key, '=') {
232 env.set(k.into(), v.into());
233 }
234 }
235 }
196 _ => panic!("bad component: {:?}", component), 236 _ => panic!("bad component: {:?}", component),
197 } 237 }
198 } 238 }
199 239
200 ParsedMeta::File(FileMeta { path, krate, deps, edition, cfg }) 240 ParsedMeta::File(FileMeta { path, krate, deps, edition, cfg, env })
201} 241}
202 242
203fn split1(haystack: &str, delim: char) -> Option<(&str, &str)> { 243fn split1(haystack: &str, delim: char) -> Option<(&str, &str)> {
diff --git a/crates/ra_db/src/input.rs b/crates/ra_db/src/input.rs
index eaff99fd3..06d40db96 100644
--- a/crates/ra_db/src/input.rs
+++ b/crates/ra_db/src/input.rs
@@ -6,7 +6,7 @@
6//! actual IO. See `vfs` and `project_model` in the `rust-analyzer` crate for how 6//! actual IO. See `vfs` and `project_model` in the `rust-analyzer` crate for how
7//! actual IO is done and lowered to input. 7//! actual IO is done and lowered to input.
8 8
9use std::{fmt, str::FromStr}; 9use std::{fmt, ops, str::FromStr};
10 10
11use ra_cfg::CfgOptions; 11use ra_cfg::CfgOptions;
12use ra_syntax::SmolStr; 12use ra_syntax::SmolStr;
@@ -86,7 +86,7 @@ pub struct CrateId(pub u32);
86pub struct CrateName(SmolStr); 86pub struct CrateName(SmolStr);
87 87
88impl CrateName { 88impl CrateName {
89 /// Crates a crate name, checking for dashes in the string provided. 89 /// Creates a crate name, checking for dashes in the string provided.
90 /// Dashes are not allowed in the crate names, 90 /// Dashes are not allowed in the crate names,
91 /// hence the input string is returned as `Err` for those cases. 91 /// hence the input string is returned as `Err` for those cases.
92 pub fn new(name: &str) -> Result<CrateName, &str> { 92 pub fn new(name: &str) -> Result<CrateName, &str> {
@@ -97,19 +97,24 @@ impl CrateName {
97 } 97 }
98 } 98 }
99 99
100 /// Crates a crate name, unconditionally replacing the dashes with underscores. 100 /// Creates a crate name, unconditionally replacing the dashes with underscores.
101 pub fn normalize_dashes(name: &str) -> CrateName { 101 pub fn normalize_dashes(name: &str) -> CrateName {
102 Self(SmolStr::new(name.replace('-', "_"))) 102 Self(SmolStr::new(name.replace('-', "_")))
103 } 103 }
104} 104}
105 105
106#[derive(Debug, Clone, PartialEq, Eq)] 106#[derive(Debug, Clone, PartialEq, Eq)]
107struct CrateData { 107pub struct CrateData {
108 file_id: FileId, 108 pub root_file_id: FileId,
109 edition: Edition, 109 pub edition: Edition,
110 cfg_options: CfgOptions, 110 /// The name to display to the end user.
111 env: Env, 111 /// This actual crate name can be different in a particular dependent crate
112 dependencies: Vec<Dependency>, 112 /// or may even be missing for some cases, such as a dummy crate for the code snippet.
113 pub display_name: Option<String>,
114 pub cfg_options: CfgOptions,
115 pub env: Env,
116 pub extern_source: ExternSource,
117 pub dependencies: Vec<Dependency>,
113} 118}
114 119
115#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 120#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
@@ -118,11 +123,22 @@ pub enum Edition {
118 Edition2015, 123 Edition2015,
119} 124}
120 125
126#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
127pub struct ExternSourceId(pub u32);
128
121#[derive(Default, Debug, Clone, PartialEq, Eq)] 129#[derive(Default, Debug, Clone, PartialEq, Eq)]
122pub struct Env { 130pub struct Env {
123 entries: FxHashMap<String, String>, 131 entries: FxHashMap<String, String>,
124} 132}
125 133
134// FIXME: Redesign vfs for solve the following limitation ?
135// Note: Some env variables (e.g. OUT_DIR) are located outside of the
136// crate. We store a map to allow remap it to ExternSourceId
137#[derive(Default, Debug, Clone, PartialEq, Eq)]
138pub struct ExternSource {
139 extern_paths: FxHashMap<String, ExternSourceId>,
140}
141
126#[derive(Debug, Clone, PartialEq, Eq)] 142#[derive(Debug, Clone, PartialEq, Eq)]
127pub struct Dependency { 143pub struct Dependency {
128 pub crate_id: CrateId, 144 pub crate_id: CrateId,
@@ -134,20 +150,26 @@ impl CrateGraph {
134 &mut self, 150 &mut self,
135 file_id: FileId, 151 file_id: FileId,
136 edition: Edition, 152 edition: Edition,
153 display_name: Option<String>,
137 cfg_options: CfgOptions, 154 cfg_options: CfgOptions,
138 env: Env, 155 env: Env,
156 extern_source: ExternSource,
139 ) -> CrateId { 157 ) -> CrateId {
140 let data = CrateData::new(file_id, edition, cfg_options, env); 158 let data = CrateData {
159 root_file_id: file_id,
160 edition,
161 display_name,
162 cfg_options,
163 env,
164 extern_source,
165 dependencies: Vec::new(),
166 };
141 let crate_id = CrateId(self.arena.len() as u32); 167 let crate_id = CrateId(self.arena.len() as u32);
142 let prev = self.arena.insert(crate_id, data); 168 let prev = self.arena.insert(crate_id, data);
143 assert!(prev.is_none()); 169 assert!(prev.is_none());
144 crate_id 170 crate_id
145 } 171 }
146 172
147 pub fn cfg_options(&self, crate_id: CrateId) -> &CfgOptions {
148 &self.arena[&crate_id].cfg_options
149 }
150
151 pub fn add_dep( 173 pub fn add_dep(
152 &mut self, 174 &mut self,
153 from: CrateId, 175 from: CrateId,
@@ -169,24 +191,13 @@ impl CrateGraph {
169 self.arena.keys().copied() 191 self.arena.keys().copied()
170 } 192 }
171 193
172 pub fn crate_root(&self, crate_id: CrateId) -> FileId {
173 self.arena[&crate_id].file_id
174 }
175
176 pub fn edition(&self, crate_id: CrateId) -> Edition {
177 self.arena[&crate_id].edition
178 }
179
180 // FIXME: this only finds one crate with the given root; we could have multiple 194 // FIXME: this only finds one crate with the given root; we could have multiple
181 pub fn crate_id_for_crate_root(&self, file_id: FileId) -> Option<CrateId> { 195 pub fn crate_id_for_crate_root(&self, file_id: FileId) -> Option<CrateId> {
182 let (&crate_id, _) = self.arena.iter().find(|(_crate_id, data)| data.file_id == file_id)?; 196 let (&crate_id, _) =
197 self.arena.iter().find(|(_crate_id, data)| data.root_file_id == file_id)?;
183 Some(crate_id) 198 Some(crate_id)
184 } 199 }
185 200
186 pub fn dependencies(&self, crate_id: CrateId) -> impl Iterator<Item = &Dependency> {
187 self.arena[&crate_id].dependencies.iter()
188 }
189
190 /// Extends this crate graph by adding a complete disjoint second crate 201 /// Extends this crate graph by adding a complete disjoint second crate
191 /// graph. 202 /// graph.
192 /// 203 ///
@@ -209,8 +220,8 @@ impl CrateGraph {
209 return false; 220 return false;
210 } 221 }
211 222
212 for dep in self.dependencies(from) { 223 for dep in &self[from].dependencies {
213 let crate_id = dep.crate_id(); 224 let crate_id = dep.crate_id;
214 if crate_id == target { 225 if crate_id == target {
215 return true; 226 return true;
216 } 227 }
@@ -223,6 +234,13 @@ impl CrateGraph {
223 } 234 }
224} 235}
225 236
237impl ops::Index<CrateId> for CrateGraph {
238 type Output = CrateData;
239 fn index(&self, crate_id: CrateId) -> &CrateData {
240 &self.arena[&crate_id]
241 }
242}
243
226impl CrateId { 244impl CrateId {
227 pub fn shift(self, amount: u32) -> CrateId { 245 pub fn shift(self, amount: u32) -> CrateId {
228 CrateId(self.0 + amount) 246 CrateId(self.0 + amount)
@@ -230,10 +248,6 @@ impl CrateId {
230} 248}
231 249
232impl CrateData { 250impl CrateData {
233 fn new(file_id: FileId, edition: Edition, cfg_options: CfgOptions, env: Env) -> CrateData {
234 CrateData { file_id, edition, dependencies: Vec::new(), cfg_options, env }
235 }
236
237 fn add_dep(&mut self, name: SmolStr, crate_id: CrateId) { 251 fn add_dep(&mut self, name: SmolStr, crate_id: CrateId) {
238 self.dependencies.push(Dependency { name, crate_id }) 252 self.dependencies.push(Dependency { name, crate_id })
239 } 253 }
@@ -261,9 +275,34 @@ impl fmt::Display for Edition {
261 } 275 }
262} 276}
263 277
264impl Dependency { 278impl Env {
265 pub fn crate_id(&self) -> CrateId { 279 pub fn set(&mut self, env: &str, value: String) {
266 self.crate_id 280 self.entries.insert(env.to_owned(), value);
281 }
282
283 pub fn get(&self, env: &str) -> Option<String> {
284 self.entries.get(env).cloned()
285 }
286}
287
288impl ExternSource {
289 pub fn extern_path(&self, path: &str) -> Option<(ExternSourceId, RelativePathBuf)> {
290 self.extern_paths.iter().find_map(|(root_path, id)| {
291 if path.starts_with(root_path) {
292 let mut rel_path = &path[root_path.len()..];
293 if rel_path.starts_with("/") {
294 rel_path = &rel_path[1..];
295 }
296 let rel_path = RelativePathBuf::from_path(rel_path).ok()?;
297 Some((id.clone(), rel_path))
298 } else {
299 None
300 }
301 })
302 }
303
304 pub fn set_extern_path(&mut self, root_path: &str, root: ExternSourceId) {
305 self.extern_paths.insert(root_path.to_owned(), root);
267 } 306 }
268} 307}
269 308
@@ -290,12 +329,30 @@ mod tests {
290 #[test] 329 #[test]
291 fn it_should_panic_because_of_cycle_dependencies() { 330 fn it_should_panic_because_of_cycle_dependencies() {
292 let mut graph = CrateGraph::default(); 331 let mut graph = CrateGraph::default();
293 let crate1 = 332 let crate1 = graph.add_crate_root(
294 graph.add_crate_root(FileId(1u32), Edition2018, CfgOptions::default(), Env::default()); 333 FileId(1u32),
295 let crate2 = 334 Edition2018,
296 graph.add_crate_root(FileId(2u32), Edition2018, CfgOptions::default(), Env::default()); 335 None,
297 let crate3 = 336 CfgOptions::default(),
298 graph.add_crate_root(FileId(3u32), Edition2018, CfgOptions::default(), Env::default()); 337 Env::default(),
338 Default::default(),
339 );
340 let crate2 = graph.add_crate_root(
341 FileId(2u32),
342 Edition2018,
343 None,
344 CfgOptions::default(),
345 Env::default(),
346 Default::default(),
347 );
348 let crate3 = graph.add_crate_root(
349 FileId(3u32),
350 Edition2018,
351 None,
352 CfgOptions::default(),
353 Env::default(),
354 Default::default(),
355 );
299 assert!(graph.add_dep(crate1, CrateName::new("crate2").unwrap(), crate2).is_ok()); 356 assert!(graph.add_dep(crate1, CrateName::new("crate2").unwrap(), crate2).is_ok());
300 assert!(graph.add_dep(crate2, CrateName::new("crate3").unwrap(), crate3).is_ok()); 357 assert!(graph.add_dep(crate2, CrateName::new("crate3").unwrap(), crate3).is_ok());
301 assert!(graph.add_dep(crate3, CrateName::new("crate1").unwrap(), crate1).is_err()); 358 assert!(graph.add_dep(crate3, CrateName::new("crate1").unwrap(), crate1).is_err());
@@ -304,12 +361,30 @@ mod tests {
304 #[test] 361 #[test]
305 fn it_works() { 362 fn it_works() {
306 let mut graph = CrateGraph::default(); 363 let mut graph = CrateGraph::default();
307 let crate1 = 364 let crate1 = graph.add_crate_root(
308 graph.add_crate_root(FileId(1u32), Edition2018, CfgOptions::default(), Env::default()); 365 FileId(1u32),
309 let crate2 = 366 Edition2018,
310 graph.add_crate_root(FileId(2u32), Edition2018, CfgOptions::default(), Env::default()); 367 None,
311 let crate3 = 368 CfgOptions::default(),
312 graph.add_crate_root(FileId(3u32), Edition2018, CfgOptions::default(), Env::default()); 369 Env::default(),
370 Default::default(),
371 );
372 let crate2 = graph.add_crate_root(
373 FileId(2u32),
374 Edition2018,
375 None,
376 CfgOptions::default(),
377 Env::default(),
378 Default::default(),
379 );
380 let crate3 = graph.add_crate_root(
381 FileId(3u32),
382 Edition2018,
383 None,
384 CfgOptions::default(),
385 Env::default(),
386 Default::default(),
387 );
313 assert!(graph.add_dep(crate1, CrateName::new("crate2").unwrap(), crate2).is_ok()); 388 assert!(graph.add_dep(crate1, CrateName::new("crate2").unwrap(), crate2).is_ok());
314 assert!(graph.add_dep(crate2, CrateName::new("crate3").unwrap(), crate3).is_ok()); 389 assert!(graph.add_dep(crate2, CrateName::new("crate3").unwrap(), crate3).is_ok());
315 } 390 }
@@ -317,16 +392,28 @@ mod tests {
317 #[test] 392 #[test]
318 fn dashes_are_normalized() { 393 fn dashes_are_normalized() {
319 let mut graph = CrateGraph::default(); 394 let mut graph = CrateGraph::default();
320 let crate1 = 395 let crate1 = graph.add_crate_root(
321 graph.add_crate_root(FileId(1u32), Edition2018, CfgOptions::default(), Env::default()); 396 FileId(1u32),
322 let crate2 = 397 Edition2018,
323 graph.add_crate_root(FileId(2u32), Edition2018, CfgOptions::default(), Env::default()); 398 None,
399 CfgOptions::default(),
400 Env::default(),
401 Default::default(),
402 );
403 let crate2 = graph.add_crate_root(
404 FileId(2u32),
405 Edition2018,
406 None,
407 CfgOptions::default(),
408 Env::default(),
409 Default::default(),
410 );
324 assert!(graph 411 assert!(graph
325 .add_dep(crate1, CrateName::normalize_dashes("crate-name-with-dashes"), crate2) 412 .add_dep(crate1, CrateName::normalize_dashes("crate-name-with-dashes"), crate2)
326 .is_ok()); 413 .is_ok());
327 assert_eq!( 414 assert_eq!(
328 graph.dependencies(crate1).collect::<Vec<_>>(), 415 graph[crate1].dependencies,
329 vec![&Dependency { crate_id: crate2, name: "crate_name_with_dashes".into() }] 416 vec![Dependency { crate_id: crate2, name: "crate_name_with_dashes".into() }]
330 ); 417 );
331 } 418 }
332} 419}
diff --git a/crates/ra_db/src/lib.rs b/crates/ra_db/src/lib.rs
index fb002d717..d500d5e85 100644
--- a/crates/ra_db/src/lib.rs
+++ b/crates/ra_db/src/lib.rs
@@ -11,7 +11,8 @@ use ra_syntax::{ast, Parse, SourceFile, TextRange, TextUnit};
11pub use crate::{ 11pub use crate::{
12 cancellation::Canceled, 12 cancellation::Canceled,
13 input::{ 13 input::{
14 CrateGraph, CrateId, CrateName, Dependency, Edition, Env, FileId, SourceRoot, SourceRootId, 14 CrateGraph, CrateId, CrateName, Dependency, Edition, Env, ExternSource, ExternSourceId,
15 FileId, SourceRoot, SourceRootId,
15 }, 16 },
16}; 17};
17pub use relative_path::{RelativePath, RelativePathBuf}; 18pub use relative_path::{RelativePath, RelativePathBuf};
@@ -87,6 +88,12 @@ pub trait FileLoader {
87 fn resolve_relative_path(&self, anchor: FileId, relative_path: &RelativePath) 88 fn resolve_relative_path(&self, anchor: FileId, relative_path: &RelativePath)
88 -> Option<FileId>; 89 -> Option<FileId>;
89 fn relevant_crates(&self, file_id: FileId) -> Arc<Vec<CrateId>>; 90 fn relevant_crates(&self, file_id: FileId) -> Arc<Vec<CrateId>>;
91
92 fn resolve_extern_path(
93 &self,
94 extern_id: ExternSourceId,
95 relative_path: &RelativePath,
96 ) -> Option<FileId>;
90} 97}
91 98
92/// Database which stores all significant input facts: source code and project 99/// Database which stores all significant input facts: source code and project
@@ -164,4 +171,13 @@ impl<T: SourceDatabaseExt> FileLoader for FileLoaderDelegate<&'_ T> {
164 let source_root = self.0.file_source_root(file_id); 171 let source_root = self.0.file_source_root(file_id);
165 self.0.source_root_crates(source_root) 172 self.0.source_root_crates(source_root)
166 } 173 }
174
175 fn resolve_extern_path(
176 &self,
177 extern_id: ExternSourceId,
178 relative_path: &RelativePath,
179 ) -> Option<FileId> {
180 let source_root = self.0.source_root(SourceRootId(extern_id.0));
181 source_root.file_by_relative_path(&relative_path)
182 }
167} 183}