1
1
use std:: collections:: BTreeMap ;
2
- use std:: io;
3
2
use std:: path:: { Path , PathBuf } ;
4
3
5
4
use syntax:: ast;
@@ -8,25 +7,157 @@ use syntax::source_map;
8
7
use syntax_pos:: symbol:: Symbol ;
9
8
10
9
use crate :: config:: FileName ;
10
+ use crate :: items:: is_mod_decl;
11
11
use crate :: utils:: contains_skip;
12
12
13
- /// List all the files containing modules of a crate.
14
- /// If a file is used twice in a crate, it appears only once.
15
- pub fn list_files < ' a > (
16
- krate : & ' a ast:: Crate ,
17
- source_map : & source_map:: SourceMap ,
18
- ) -> Result < BTreeMap < FileName , & ' a ast:: Mod > , io:: Error > {
19
- let mut result = BTreeMap :: new ( ) ; // Enforce file order determinism
20
- let root_filename = source_map. span_to_filename ( krate. span ) ;
21
- {
22
- let parent = match root_filename {
23
- source_map:: FileName :: Real ( ref path) => path. parent ( ) . unwrap ( ) ,
24
- _ => Path :: new ( "" ) ,
13
+ type FileModMap < ' a > = BTreeMap < FileName , ( & ' a ast:: Mod , & ' a str ) > ;
14
+
15
+ /// Maps each module to the corresponding file.
16
+ pub struct ModResolver < ' a , ' b > {
17
+ source_map : & ' b source_map:: SourceMap ,
18
+ directory : Directory ,
19
+ file_map : FileModMap < ' a > ,
20
+ is_input_stdin : bool ,
21
+ }
22
+
23
+ #[ derive( Clone ) ]
24
+ struct Directory {
25
+ path : PathBuf ,
26
+ ownership : DirectoryOwnership ,
27
+ }
28
+
29
+ impl < ' a , ' b > ModResolver < ' a , ' b > {
30
+ /// Creates a new `ModResolver`.
31
+ pub fn new (
32
+ source_map : & ' b source_map:: SourceMap ,
33
+ directory_ownership : DirectoryOwnership ,
34
+ is_input_stdin : bool ,
35
+ ) -> Self {
36
+ ModResolver {
37
+ directory : Directory {
38
+ path : PathBuf :: new ( ) ,
39
+ ownership : directory_ownership,
40
+ } ,
41
+ file_map : BTreeMap :: new ( ) ,
42
+ source_map,
43
+ is_input_stdin,
44
+ }
45
+ }
46
+
47
+ /// Creates a map that maps a file name to the module in AST.
48
+ pub fn visit_crate ( mut self , krate : & ' a ast:: Crate ) -> Result < FileModMap < ' a > , String > {
49
+ let root_filename = self . source_map . span_to_filename ( krate. span ) ;
50
+ self . directory . path = match root_filename {
51
+ source_map:: FileName :: Real ( ref path) => path
52
+ . parent ( )
53
+ . expect ( "Parent directory should exists" )
54
+ . to_path_buf ( ) ,
55
+ _ => PathBuf :: new ( ) ,
56
+ } ;
57
+
58
+ // Skip visiting sub modules when the input is from stdin.
59
+ if !self . is_input_stdin {
60
+ self . visit_mod ( & krate. module ) ?;
61
+ }
62
+
63
+ self . file_map
64
+ . insert ( root_filename. into ( ) , ( & krate. module , "" ) ) ;
65
+ Ok ( self . file_map )
66
+ }
67
+
68
+ fn visit_mod ( & mut self , module : & ' a ast:: Mod ) -> Result < ( ) , String > {
69
+ for item in & module. items {
70
+ if let ast:: ItemKind :: Mod ( ref sub_mod) = item. node {
71
+ if contains_skip ( & item. attrs ) {
72
+ continue ;
73
+ }
74
+
75
+ let old_direcotry = self . directory . clone ( ) ;
76
+ if is_mod_decl ( item) {
77
+ // mod foo;
78
+ // Look for an extern file.
79
+ let ( mod_path, directory_ownership) =
80
+ self . find_external_module ( item. ident , & item. attrs ) ?;
81
+ self . file_map . insert (
82
+ FileName :: Real ( mod_path. clone ( ) ) ,
83
+ ( sub_mod, item. ident . name . as_str ( ) . get ( ) ) ,
84
+ ) ;
85
+ self . directory = Directory {
86
+ path : mod_path. parent ( ) . unwrap ( ) . to_path_buf ( ) ,
87
+ ownership : directory_ownership,
88
+ }
89
+ } else {
90
+ // An internal module (`mod foo { /* ... */ }`);
91
+ if let Some ( path) = find_path_value ( & item. attrs ) {
92
+ // All `#[path]` files are treated as though they are a `mod.rs` file.
93
+ self . directory = Directory {
94
+ path : Path :: new ( & path. as_str ( ) ) . to_path_buf ( ) ,
95
+ ownership : DirectoryOwnership :: Owned { relative : None } ,
96
+ } ;
97
+ } else {
98
+ self . push_inline_mod_directory ( item. ident , & item. attrs ) ;
99
+ }
100
+ }
101
+ self . visit_mod ( sub_mod) ?;
102
+ self . directory = old_direcotry;
103
+ }
104
+ }
105
+ Ok ( ( ) )
106
+ }
107
+
108
+ fn find_external_module (
109
+ & self ,
110
+ mod_name : ast:: Ident ,
111
+ attrs : & [ ast:: Attribute ] ,
112
+ ) -> Result < ( PathBuf , DirectoryOwnership ) , String > {
113
+ if let Some ( path) = parser:: Parser :: submod_path_from_attr ( attrs, & self . directory . path ) {
114
+ return Ok ( ( path, DirectoryOwnership :: Owned { relative : None } ) ) ;
115
+ }
116
+
117
+ let relative = match self . directory . ownership {
118
+ DirectoryOwnership :: Owned { relative } => relative,
119
+ DirectoryOwnership :: UnownedViaBlock | DirectoryOwnership :: UnownedViaMod ( _) => None ,
25
120
} ;
26
- list_submodules ( & krate. module , parent, None , source_map, & mut result) ?;
121
+ match parser:: Parser :: default_submod_path (
122
+ mod_name,
123
+ relative,
124
+ & self . directory . path ,
125
+ self . source_map ,
126
+ )
127
+ . result
128
+ {
129
+ Ok ( parser:: ModulePathSuccess {
130
+ path,
131
+ directory_ownership,
132
+ ..
133
+ } ) => Ok ( ( path, directory_ownership) ) ,
134
+ Err ( _) => Err ( format ! (
135
+ "Failed to find module {} in {:?} {:?}" ,
136
+ mod_name, self . directory. path, relative,
137
+ ) ) ,
138
+ }
139
+ }
140
+
141
+ fn push_inline_mod_directory ( & mut self , id : ast:: Ident , attrs : & [ ast:: Attribute ] ) {
142
+ if let Some ( path) = find_path_value ( attrs) {
143
+ self . directory . path . push ( & path. as_str ( ) ) ;
144
+ self . directory . ownership = DirectoryOwnership :: Owned { relative : None } ;
145
+ } else {
146
+ // We have to push on the current module name in the case of relative
147
+ // paths in order to ensure that any additional module paths from inline
148
+ // `mod x { ... }` come after the relative extension.
149
+ //
150
+ // For example, a `mod z { ... }` inside `x/y.rs` should set the current
151
+ // directory path to `/x/y/z`, not `/x/z` with a relative offset of `y`.
152
+ if let DirectoryOwnership :: Owned { relative } = & mut self . directory . ownership {
153
+ if let Some ( ident) = relative. take ( ) {
154
+ // remove the relative offset
155
+ self . directory . path . push ( ident. as_str ( ) ) ;
156
+ }
157
+ }
158
+ self . directory . path . push ( & id. as_str ( ) ) ;
159
+ }
27
160
}
28
- result. insert ( root_filename. into ( ) , & krate. module ) ;
29
- Ok ( result)
30
161
}
31
162
32
163
fn path_value ( attr : & ast:: Attribute ) -> Option < Symbol > {
@@ -43,69 +174,3 @@ fn path_value(attr: &ast::Attribute) -> Option<Symbol> {
43
174
fn find_path_value ( attrs : & [ ast:: Attribute ] ) -> Option < Symbol > {
44
175
attrs. iter ( ) . flat_map ( path_value) . next ( )
45
176
}
46
-
47
- /// Recursively list all external modules included in a module.
48
- fn list_submodules < ' a > (
49
- module : & ' a ast:: Mod ,
50
- search_dir : & Path ,
51
- relative : Option < ast:: Ident > ,
52
- source_map : & source_map:: SourceMap ,
53
- result : & mut BTreeMap < FileName , & ' a ast:: Mod > ,
54
- ) -> Result < ( ) , io:: Error > {
55
- debug ! ( "list_submodules: search_dir: {:?}" , search_dir) ;
56
- for item in & module. items {
57
- if let ast:: ItemKind :: Mod ( ref sub_mod) = item. node {
58
- if !contains_skip ( & item. attrs ) {
59
- let is_internal = source_map. span_to_filename ( item. span )
60
- == source_map. span_to_filename ( sub_mod. inner ) ;
61
- let ( dir_path, relative) = if is_internal {
62
- if let Some ( path) = find_path_value ( & item. attrs ) {
63
- ( search_dir. join ( & path. as_str ( ) ) , None )
64
- } else {
65
- ( search_dir. join ( & item. ident . to_string ( ) ) , None )
66
- }
67
- } else {
68
- let ( mod_path, relative) =
69
- module_file ( item. ident , & item. attrs , search_dir, relative, source_map) ?;
70
- let dir_path = mod_path. parent ( ) . unwrap ( ) . to_owned ( ) ;
71
- result. insert ( FileName :: Real ( mod_path) , sub_mod) ;
72
- ( dir_path, relative)
73
- } ;
74
- list_submodules ( sub_mod, & dir_path, relative, source_map, result) ?;
75
- }
76
- }
77
- }
78
- Ok ( ( ) )
79
- }
80
-
81
- /// Finds the file corresponding to an external mod
82
- fn module_file (
83
- id : ast:: Ident ,
84
- attrs : & [ ast:: Attribute ] ,
85
- dir_path : & Path ,
86
- relative : Option < ast:: Ident > ,
87
- source_map : & source_map:: SourceMap ,
88
- ) -> Result < ( PathBuf , Option < ast:: Ident > ) , io:: Error > {
89
- if let Some ( path) = parser:: Parser :: submod_path_from_attr ( attrs, dir_path) {
90
- return Ok ( ( path, None ) ) ;
91
- }
92
-
93
- match parser:: Parser :: default_submod_path ( id, relative, dir_path, source_map) . result {
94
- Ok ( parser:: ModulePathSuccess {
95
- path,
96
- directory_ownership,
97
- ..
98
- } ) => {
99
- let relative = if let DirectoryOwnership :: Owned { relative } = directory_ownership {
100
- relative
101
- } else {
102
- None
103
- } ;
104
- Ok ( ( path, relative) )
105
- }
106
- Err ( _) => Err ( io:: Error :: new (
107
- io:: ErrorKind :: Other ,
108
- format ! ( "Couldn't find module {}" , id) ,
109
- ) ) ,
110
- }
111
- }
0 commit comments