@@ -57,15 +57,17 @@ mod tests;
57
57
58
58
use std:: sync:: Arc ;
59
59
60
- use either:: Either ;
61
60
use hir_expand:: {
62
61
ast_id_map:: FileAstId , diagnostics:: DiagnosticSink , name:: Name , InFile , MacroDefId ,
63
62
} ;
64
63
use once_cell:: sync:: Lazy ;
65
64
use ra_arena:: Arena ;
66
- use ra_db:: { CrateId , Edition , FileId } ;
65
+ use ra_db:: { CrateId , Edition , FileId , FilePosition } ;
67
66
use ra_prof:: profile;
68
- use ra_syntax:: ast;
67
+ use ra_syntax:: {
68
+ ast:: { self , AstNode } ,
69
+ SyntaxNode ,
70
+ } ;
69
71
use rustc_hash:: FxHashMap ;
70
72
71
73
use crate :: {
@@ -100,19 +102,76 @@ impl std::ops::Index<LocalModuleId> for CrateDefMap {
100
102
}
101
103
}
102
104
105
+ #[ derive( Debug , PartialEq , Eq , Clone , Copy , Hash ) ]
106
+ pub enum ModuleOrigin {
107
+ CrateRoot {
108
+ definition : FileId ,
109
+ } ,
110
+ /// Note that non-inline modules, by definition, live inside non-macro file.
111
+ File {
112
+ declaration : AstId < ast:: Module > ,
113
+ definition : FileId ,
114
+ } ,
115
+ Inline {
116
+ definition : AstId < ast:: Module > ,
117
+ } ,
118
+ }
119
+
120
+ impl Default for ModuleOrigin {
121
+ fn default ( ) -> Self {
122
+ ModuleOrigin :: CrateRoot { definition : FileId ( 0 ) }
123
+ }
124
+ }
125
+
126
+ impl ModuleOrigin {
127
+ pub ( crate ) fn not_sure_file ( file : Option < FileId > , declaration : AstId < ast:: Module > ) -> Self {
128
+ match file {
129
+ None => ModuleOrigin :: Inline { definition : declaration } ,
130
+ Some ( definition) => ModuleOrigin :: File { declaration, definition } ,
131
+ }
132
+ }
133
+
134
+ fn declaration ( & self ) -> Option < AstId < ast:: Module > > {
135
+ match self {
136
+ ModuleOrigin :: File { declaration : module, .. }
137
+ | ModuleOrigin :: Inline { definition : module, .. } => Some ( * module) ,
138
+ ModuleOrigin :: CrateRoot { .. } => None ,
139
+ }
140
+ }
141
+
142
+ pub fn file_id ( & self ) -> Option < FileId > {
143
+ match self {
144
+ ModuleOrigin :: File { definition, .. } | ModuleOrigin :: CrateRoot { definition } => {
145
+ Some ( * definition)
146
+ }
147
+ _ => None ,
148
+ }
149
+ }
150
+
151
+ /// Returns a node which defines this module.
152
+ /// That is, a file or a `mod foo {}` with items.
153
+ fn definition_source ( & self , db : & impl DefDatabase ) -> InFile < ModuleSource > {
154
+ match self {
155
+ ModuleOrigin :: File { definition, .. } | ModuleOrigin :: CrateRoot { definition } => {
156
+ let file_id = * definition;
157
+ let sf = db. parse ( file_id) . tree ( ) ;
158
+ return InFile :: new ( file_id. into ( ) , ModuleSource :: SourceFile ( sf) ) ;
159
+ }
160
+ ModuleOrigin :: Inline { definition } => {
161
+ InFile :: new ( definition. file_id , ModuleSource :: Module ( definition. to_node ( db) ) )
162
+ }
163
+ }
164
+ }
165
+ }
166
+
103
167
#[ derive( Default , Debug , PartialEq , Eq ) ]
104
168
pub struct ModuleData {
105
169
pub parent : Option < LocalModuleId > ,
106
170
pub children : FxHashMap < Name , LocalModuleId > ,
107
171
pub scope : ModuleScope ,
108
172
109
- // FIXME: these can't be both null, we need a three-state enum here.
110
- /// None for root
111
- pub declaration : Option < AstId < ast:: Module > > ,
112
- /// None for inline modules.
113
- ///
114
- /// Note that non-inline modules, by definition, live inside non-macro file.
115
- pub definition : Option < FileId > ,
173
+ /// Where does this module come from?
174
+ pub origin : ModuleOrigin ,
116
175
117
176
pub impls : Vec < ImplId > ,
118
177
}
@@ -262,7 +321,7 @@ impl CrateDefMap {
262
321
pub fn modules_for_file ( & self , file_id : FileId ) -> impl Iterator < Item = LocalModuleId > + ' _ {
263
322
self . modules
264
323
. iter ( )
265
- . filter ( move |( _id, data) | data. definition == Some ( file_id) )
324
+ . filter ( move |( _id, data) | data. origin . file_id ( ) == Some ( file_id) )
266
325
. map ( |( id, _data) | id)
267
326
}
268
327
@@ -281,27 +340,54 @@ impl CrateDefMap {
281
340
282
341
impl ModuleData {
283
342
/// Returns a node which defines this module. That is, a file or a `mod foo {}` with items.
284
- pub fn definition_source (
285
- & self ,
286
- db : & impl DefDatabase ,
287
- ) -> InFile < Either < ast:: SourceFile , ast:: Module > > {
288
- if let Some ( file_id) = self . definition {
289
- let sf = db. parse ( file_id) . tree ( ) ;
290
- return InFile :: new ( file_id. into ( ) , Either :: Left ( sf) ) ;
291
- }
292
- let decl = self . declaration . unwrap ( ) ;
293
- InFile :: new ( decl. file_id , Either :: Right ( decl. to_node ( db) ) )
343
+ pub fn definition_source ( & self , db : & impl DefDatabase ) -> InFile < ModuleSource > {
344
+ self . origin . definition_source ( db)
294
345
}
295
346
296
347
/// Returns a node which declares this module, either a `mod foo;` or a `mod foo {}`.
297
- /// `None` for the crate root.
348
+ /// `None` for the crate root or block .
298
349
pub fn declaration_source ( & self , db : & impl DefDatabase ) -> Option < InFile < ast:: Module > > {
299
- let decl = self . declaration ?;
350
+ let decl = self . origin . declaration ( ) ?;
300
351
let value = decl. to_node ( db) ;
301
352
Some ( InFile { file_id : decl. file_id , value } )
302
353
}
303
354
}
304
355
356
+ #[ derive( Debug , Clone , PartialEq , Eq ) ]
357
+ pub enum ModuleSource {
358
+ SourceFile ( ast:: SourceFile ) ,
359
+ Module ( ast:: Module ) ,
360
+ }
361
+
362
+ impl ModuleSource {
363
+ // FIXME: this methods do not belong here
364
+ pub fn from_position ( db : & impl DefDatabase , position : FilePosition ) -> ModuleSource {
365
+ let parse = db. parse ( position. file_id ) ;
366
+ match & ra_syntax:: algo:: find_node_at_offset :: < ast:: Module > (
367
+ parse. tree ( ) . syntax ( ) ,
368
+ position. offset ,
369
+ ) {
370
+ Some ( m) if !m. has_semi ( ) => ModuleSource :: Module ( m. clone ( ) ) ,
371
+ _ => {
372
+ let source_file = parse. tree ( ) ;
373
+ ModuleSource :: SourceFile ( source_file)
374
+ }
375
+ }
376
+ }
377
+
378
+ pub fn from_child_node ( db : & impl DefDatabase , child : InFile < & SyntaxNode > ) -> ModuleSource {
379
+ if let Some ( m) =
380
+ child. value . ancestors ( ) . filter_map ( ast:: Module :: cast) . find ( |it| !it. has_semi ( ) )
381
+ {
382
+ ModuleSource :: Module ( m)
383
+ } else {
384
+ let file_id = child. file_id . original_file ( db) ;
385
+ let source_file = db. parse ( file_id) . tree ( ) ;
386
+ ModuleSource :: SourceFile ( source_file)
387
+ }
388
+ }
389
+ }
390
+
305
391
mod diagnostics {
306
392
use hir_expand:: diagnostics:: DiagnosticSink ;
307
393
use ra_db:: RelativePathBuf ;
0 commit comments