@@ -57,15 +57,17 @@ mod tests;
5757
5858use std:: sync:: Arc ;
5959
60- use either:: Either ;
6160use hir_expand:: {
6261 ast_id_map:: FileAstId , diagnostics:: DiagnosticSink , name:: Name , InFile , MacroDefId ,
6362} ;
6463use once_cell:: sync:: Lazy ;
6564use ra_arena:: Arena ;
66- use ra_db:: { CrateId , Edition , FileId } ;
65+ use ra_db:: { CrateId , Edition , FileId , FilePosition } ;
6766use ra_prof:: profile;
68- use ra_syntax:: ast;
67+ use ra_syntax:: {
68+ ast:: { self , AstNode } ,
69+ SyntaxNode ,
70+ } ;
6971use rustc_hash:: FxHashMap ;
7072
7173use crate :: {
@@ -100,19 +102,76 @@ impl std::ops::Index<LocalModuleId> for CrateDefMap {
100102 }
101103}
102104
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+
103167#[ derive( Default , Debug , PartialEq , Eq ) ]
104168pub struct ModuleData {
105169 pub parent : Option < LocalModuleId > ,
106170 pub children : FxHashMap < Name , LocalModuleId > ,
107171 pub scope : ModuleScope ,
108172
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 ,
116175
117176 pub impls : Vec < ImplId > ,
118177}
@@ -262,7 +321,7 @@ impl CrateDefMap {
262321 pub fn modules_for_file ( & self , file_id : FileId ) -> impl Iterator < Item = LocalModuleId > + ' _ {
263322 self . modules
264323 . iter ( )
265- . filter ( move |( _id, data) | data. definition == Some ( file_id) )
324+ . filter ( move |( _id, data) | data. origin . file_id ( ) == Some ( file_id) )
266325 . map ( |( id, _data) | id)
267326 }
268327
@@ -281,27 +340,54 @@ impl CrateDefMap {
281340
282341impl ModuleData {
283342 /// 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)
294345 }
295346
296347 /// 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 .
298349 pub fn declaration_source ( & self , db : & impl DefDatabase ) -> Option < InFile < ast:: Module > > {
299- let decl = self . declaration ?;
350+ let decl = self . origin . declaration ( ) ?;
300351 let value = decl. to_node ( db) ;
301352 Some ( InFile { file_id : decl. file_id , value } )
302353 }
303354}
304355
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+
305391mod diagnostics {
306392 use hir_expand:: diagnostics:: DiagnosticSink ;
307393 use ra_db:: RelativePathBuf ;
0 commit comments