@@ -6,6 +6,7 @@ use ra_db::{
6
6
} ;
7
7
use relative_path:: RelativePathBuf ;
8
8
use test_utils:: { parse_fixture, CURSOR_MARKER , extract_offset} ;
9
+ use rustc_hash:: FxHashMap ;
9
10
10
11
use crate :: { db, HirInterner } ;
11
12
@@ -21,82 +22,125 @@ pub struct MockDatabase {
21
22
events : Mutex < Option < Vec < salsa:: Event < MockDatabase > > > > ,
22
23
runtime : salsa:: Runtime < MockDatabase > ,
23
24
interner : Arc < HirInterner > ,
24
- file_counter : u32 ,
25
+ files : FxHashMap < String , FileId > ,
25
26
}
26
27
27
28
impl panic:: RefUnwindSafe for MockDatabase { }
28
29
29
30
impl MockDatabase {
30
- pub fn with_files ( fixture : & str ) -> ( MockDatabase , SourceRoot ) {
31
- let ( db, source_root , position) = MockDatabase :: from_fixture ( fixture) ;
31
+ pub fn with_files ( fixture : & str ) -> MockDatabase {
32
+ let ( db, position) = MockDatabase :: from_fixture ( fixture) ;
32
33
assert ! ( position. is_none( ) ) ;
33
- ( db , source_root )
34
+ db
34
35
}
35
36
36
37
pub fn with_single_file ( text : & str ) -> ( MockDatabase , SourceRoot , FileId ) {
37
38
let mut db = MockDatabase :: default ( ) ;
38
39
let mut source_root = SourceRoot :: default ( ) ;
39
- let file_id = db. add_file ( WORKSPACE , & mut source_root, "/main.rs" , text) ;
40
+ let file_id = db. add_file ( WORKSPACE , "/" , & mut source_root, "/main.rs" , text) ;
40
41
db. set_source_root ( WORKSPACE , Arc :: new ( source_root. clone ( ) ) ) ;
41
42
( db, source_root, file_id)
42
43
}
43
44
44
45
pub fn with_position ( fixture : & str ) -> ( MockDatabase , FilePosition ) {
45
- let ( db, _ , position) = MockDatabase :: from_fixture ( fixture) ;
46
+ let ( db, position) = MockDatabase :: from_fixture ( fixture) ;
46
47
let position = position. expect ( "expected a marker ( <|> )" ) ;
47
48
( db, position)
48
49
}
49
50
50
- fn from_fixture ( fixture : & str ) -> ( MockDatabase , SourceRoot , Option < FilePosition > ) {
51
+ pub fn file_id_of ( & self , path : & str ) -> FileId {
52
+ match self . files . get ( path) {
53
+ Some ( it) => * it,
54
+ None => panic ! ( "unknown file: {:?}\n existing files:\n {:#?}" , path, self . files) ,
55
+ }
56
+ }
57
+
58
+ pub fn set_crate_graph_from_fixture ( & mut self , graph : CrateGraphFixture ) {
59
+ let mut ids = FxHashMap :: default ( ) ;
60
+ let mut crate_graph = CrateGraph :: default ( ) ;
61
+ for ( crate_name, ( crate_root, _) ) in graph. 0 . iter ( ) {
62
+ let crate_root = self . file_id_of ( & crate_root) ;
63
+ let crate_id = crate_graph. add_crate_root ( crate_root) ;
64
+ ids. insert ( crate_name, crate_id) ;
65
+ }
66
+ for ( crate_name, ( _, deps) ) in graph. 0 . iter ( ) {
67
+ let from = ids[ crate_name] ;
68
+ for dep in deps {
69
+ let to = ids[ dep] ;
70
+ crate_graph. add_dep ( from, dep. as_str ( ) . into ( ) , to) . unwrap ( ) ;
71
+ }
72
+ }
73
+ self . set_crate_graph ( Arc :: new ( crate_graph) )
74
+ }
75
+
76
+ fn from_fixture ( fixture : & str ) -> ( MockDatabase , Option < FilePosition > ) {
51
77
let mut db = MockDatabase :: default ( ) ;
52
78
53
- let ( source_root , pos) = db. add_fixture ( WORKSPACE , fixture) ;
79
+ let pos = db. add_fixture ( fixture) ;
54
80
55
- ( db, source_root , pos)
81
+ ( db, pos)
56
82
}
57
83
58
- pub fn add_fixture (
59
- & mut self ,
60
- source_root_id : SourceRootId ,
61
- fixture : & str ,
62
- ) -> ( SourceRoot , Option < FilePosition > ) {
84
+ fn add_fixture ( & mut self , fixture : & str ) -> Option < FilePosition > {
63
85
let mut position = None ;
64
86
let mut source_root = SourceRoot :: default ( ) ;
87
+ let mut source_root_id = WORKSPACE ;
88
+ let mut source_root_prefix = "/" . to_string ( ) ;
65
89
for entry in parse_fixture ( fixture) {
90
+ if entry. meta . starts_with ( "root" ) {
91
+ self . set_source_root ( source_root_id, Arc :: new ( source_root) ) ;
92
+ source_root = SourceRoot :: default ( ) ;
93
+
94
+ source_root_id = SourceRootId ( source_root_id. 0 + 1 ) ;
95
+ source_root_prefix = entry. meta [ "root" . len ( ) ..] . trim ( ) . to_string ( ) ;
96
+ continue ;
97
+ }
66
98
if entry. text . contains ( CURSOR_MARKER ) {
67
99
assert ! ( position. is_none( ) , "only one marker (<|>) per fixture is allowed" ) ;
68
100
position = Some ( self . add_file_with_position (
69
101
source_root_id,
102
+ & source_root_prefix,
70
103
& mut source_root,
71
104
& entry. meta ,
72
105
& entry. text ,
73
106
) ) ;
74
107
} else {
75
- self . add_file ( source_root_id, & mut source_root, & entry. meta , & entry. text ) ;
108
+ self . add_file (
109
+ source_root_id,
110
+ & source_root_prefix,
111
+ & mut source_root,
112
+ & entry. meta ,
113
+ & entry. text ,
114
+ ) ;
76
115
}
77
116
}
78
- self . set_source_root ( source_root_id, Arc :: new ( source_root. clone ( ) ) ) ;
79
- ( source_root , position)
117
+ self . set_source_root ( source_root_id, Arc :: new ( source_root) ) ;
118
+ position
80
119
}
81
120
82
121
fn add_file (
83
122
& mut self ,
84
123
source_root_id : SourceRootId ,
124
+ source_root_prefix : & str ,
85
125
source_root : & mut SourceRoot ,
86
126
path : & str ,
87
127
text : & str ,
88
128
) -> FileId {
89
- assert ! ( path. starts_with( '/' ) ) ;
90
- let is_crate_root = path == "/lib.rs" || path == "/main.rs" ;
129
+ assert ! ( source_root_prefix. starts_with( '/' ) ) ;
130
+ assert ! ( source_root_prefix. ends_with( '/' ) ) ;
131
+ assert ! ( path. starts_with( source_root_prefix) ) ;
132
+ let rel_path = RelativePathBuf :: from_path ( & path[ source_root_prefix. len ( ) ..] ) . unwrap ( ) ;
133
+
134
+ let is_crate_root = rel_path == "lib.rs" || rel_path == "/main.rs" ;
91
135
92
- let path = RelativePathBuf :: from_path ( & path [ 1 .. ] ) . unwrap ( ) ;
93
- let file_id = FileId ( self . file_counter ) ;
94
- self . file_counter += 1 ;
136
+ let file_id = FileId ( self . files . len ( ) as u32 ) ;
137
+ let prev = self . files . insert ( path . to_string ( ) , file_id ) ;
138
+ assert ! ( prev . is_none ( ) , "duplicate files in the text fixture" ) ;
95
139
let text = Arc :: new ( text. to_string ( ) ) ;
96
140
self . set_file_text ( file_id, text) ;
97
- self . set_file_relative_path ( file_id, path . clone ( ) ) ;
141
+ self . set_file_relative_path ( file_id, rel_path . clone ( ) ) ;
98
142
self . set_file_source_root ( file_id, source_root_id) ;
99
- source_root. files . insert ( path , file_id) ;
143
+ source_root. files . insert ( rel_path , file_id) ;
100
144
101
145
if is_crate_root {
102
146
let mut crate_graph = CrateGraph :: default ( ) ;
@@ -109,12 +153,13 @@ impl MockDatabase {
109
153
fn add_file_with_position (
110
154
& mut self ,
111
155
source_root_id : SourceRootId ,
156
+ source_root_prefix : & str ,
112
157
source_root : & mut SourceRoot ,
113
158
path : & str ,
114
159
text : & str ,
115
160
) -> FilePosition {
116
161
let ( offset, text) = extract_offset ( text) ;
117
- let file_id = self . add_file ( source_root_id, source_root, path, & text) ;
162
+ let file_id = self . add_file ( source_root_id, source_root_prefix , source_root, path, & text) ;
118
163
FilePosition { file_id, offset }
119
164
}
120
165
}
@@ -138,7 +183,7 @@ impl Default for MockDatabase {
138
183
events : Default :: default ( ) ,
139
184
runtime : salsa:: Runtime :: default ( ) ,
140
185
interner : Default :: default ( ) ,
141
- file_counter : 0 ,
186
+ files : FxHashMap :: default ( ) ,
142
187
} ;
143
188
db. set_crate_graph ( Default :: default ( ) ) ;
144
189
db
@@ -151,7 +196,8 @@ impl salsa::ParallelDatabase for MockDatabase {
151
196
events : Default :: default ( ) ,
152
197
runtime : self . runtime . snapshot ( self ) ,
153
198
interner : Arc :: clone ( & self . interner ) ,
154
- file_counter : self . file_counter ,
199
+ // only the root database can be used to get file_id by path.
200
+ files : FxHashMap :: default ( ) ,
155
201
} )
156
202
}
157
203
}
@@ -184,3 +230,20 @@ impl MockDatabase {
184
230
. collect ( )
185
231
}
186
232
}
233
+
234
+ #[ derive( Default ) ]
235
+ pub struct CrateGraphFixture ( pub FxHashMap < String , ( String , Vec < String > ) > ) ;
236
+
237
+ #[ macro_export]
238
+ macro_rules! crate_graph {
239
+ ( $( $crate_name: literal: ( $crate_path: literal, [ $( $dep: literal) ,* ] ) , ) * ) => { {
240
+ let mut res = $crate:: mock:: CrateGraphFixture :: default ( ) ;
241
+ $(
242
+ res. 0 . insert(
243
+ $crate_name. to_string( ) ,
244
+ ( $crate_path. to_string( ) , vec![ $( $dep. to_string( ) ) ,* ] )
245
+ ) ;
246
+ ) *
247
+ res
248
+ } }
249
+ }
0 commit comments