2 use super::item
::ItemInfo
;
3 use super::diagnostics
::Error
;
5 use crate::{new_sub_parser_from_file, DirectoryOwnership}
;
7 use rustc_errors
::PResult
;
9 use syntax
::ast
::{self, Ident, Attribute, ItemKind, Mod, Crate}
;
10 use syntax
::token
::{self, TokenKind}
;
11 use syntax_pos
::source_map
::{SourceMap, Span, DUMMY_SP, FileName}
;
12 use syntax_pos
::symbol
::sym
;
14 use std
::path
::{self, Path, PathBuf}
;
16 /// Information about the path to a module.
17 pub(super) struct ModulePath
{
20 pub result
: Result
<ModulePathSuccess
, Error
>,
23 pub(super) struct ModulePathSuccess
{
25 pub directory_ownership
: DirectoryOwnership
,
29 /// Parses a source module as a crate. This is the main entry point for the parser.
30 pub fn parse_crate_mod(&mut self) -> PResult
<'a
, Crate
> {
31 let lo
= self.token
.span
;
32 let krate
= Ok(ast
::Crate
{
33 attrs
: self.parse_inner_attributes()?
,
34 module
: self.parse_mod_items(&token
::Eof
, lo
)?
,
35 span
: lo
.to(self.token
.span
),
40 /// Parses a `mod <foo> { ... }` or `mod <foo>;` item.
41 pub(super) fn parse_item_mod(&mut self, outer_attrs
: &[Attribute
]) -> PResult
<'a
, ItemInfo
> {
42 let (in_cfg
, outer_attrs
) = crate::config
::process_configure_mod(
48 let id_span
= self.token
.span
;
49 let id
= self.parse_ident()?
;
50 if self.eat(&token
::Semi
) {
51 if in_cfg
&& self.recurse_into_file_modules
{
52 // This mod is in an external file. Let's go get it!
53 let ModulePathSuccess { path, directory_ownership }
=
54 self.submod_path(id
, &outer_attrs
, id_span
)?
;
56 self.eval_src_mod(path
, directory_ownership
, id
.to_string(), id_span
)?
;
57 Ok((id
, ItemKind
::Mod(module
), Some(attrs
)))
59 let placeholder
= ast
::Mod
{
64 Ok((id
, ItemKind
::Mod(placeholder
), None
))
67 let old_directory
= self.directory
.clone();
68 self.push_directory(id
, &outer_attrs
);
70 self.expect(&token
::OpenDelim(token
::Brace
))?
;
71 let mod_inner_lo
= self.token
.span
;
72 let attrs
= self.parse_inner_attributes()?
;
73 let module
= self.parse_mod_items(&token
::CloseDelim(token
::Brace
), mod_inner_lo
)?
;
75 self.directory
= old_directory
;
76 Ok((id
, ItemKind
::Mod(module
), Some(attrs
)))
80 /// Given a termination token, parses all of the items in a module.
81 fn parse_mod_items(&mut self, term
: &TokenKind
, inner_lo
: Span
) -> PResult
<'a
, Mod
> {
82 let mut items
= vec
![];
83 while let Some(item
) = self.parse_item()?
{
85 self.maybe_consume_incorrect_semicolon(&items
);
89 let token_str
= self.this_token_descr();
90 if !self.maybe_consume_incorrect_semicolon(&items
) {
91 let mut err
= self.fatal(&format
!("expected item, found {}", token_str
));
92 err
.span_label(self.token
.span
, "expected item");
97 let hi
= if self.token
.span
.is_dummy() {
104 inner
: inner_lo
.to(hi
),
113 outer_attrs
: &[Attribute
],
115 ) -> PResult
<'a
, ModulePathSuccess
> {
116 if let Some(path
) = Parser
::submod_path_from_attr(outer_attrs
, &self.directory
.path
) {
117 return Ok(ModulePathSuccess
{
118 directory_ownership
: match path
.file_name().and_then(|s
| s
.to_str()) {
119 // All `#[path]` files are treated as though they are a `mod.rs` file.
120 // This means that `mod foo;` declarations inside `#[path]`-included
121 // files are siblings,
123 // Note that this will produce weirdness when a file named `foo.rs` is
124 // `#[path]` included and contains a `mod foo;` declaration.
125 // If you encounter this, it's your own darn fault :P
126 Some(_
) => DirectoryOwnership
::Owned { relative: None }
,
127 _
=> DirectoryOwnership
::UnownedViaMod
,
133 let relative
= match self.directory
.ownership
{
134 DirectoryOwnership
::Owned { relative }
=> relative
,
135 DirectoryOwnership
::UnownedViaBlock
|
136 DirectoryOwnership
::UnownedViaMod
=> None
,
138 let paths
= Parser
::default_submod_path(
139 id
, relative
, &self.directory
.path
, self.sess
.source_map());
141 match self.directory
.ownership
{
142 DirectoryOwnership
::Owned { .. }
=> {
143 paths
.result
.map_err(|err
| self.span_fatal_err(id_sp
, err
))
145 DirectoryOwnership
::UnownedViaBlock
=> {
147 "Cannot declare a non-inline module inside a block \
148 unless it has a path attribute";
149 let mut err
= self.diagnostic().struct_span_err(id_sp
, msg
);
150 if paths
.path_exists
{
151 let msg
= format
!("Maybe `use` the module `{}` instead of redeclaring it",
153 err
.span_note(id_sp
, &msg
);
157 DirectoryOwnership
::UnownedViaMod
=> {
158 let mut err
= self.diagnostic().struct_span_err(id_sp
,
159 "cannot declare a new module at this location");
160 if !id_sp
.is_dummy() {
161 let src_path
= self.sess
.source_map().span_to_filename(id_sp
);
162 if let FileName
::Real(src_path
) = src_path
{
163 if let Some(stem
) = src_path
.file_stem() {
164 let mut dest_path
= src_path
.clone();
165 dest_path
.set_file_name(stem
);
166 dest_path
.push("mod.rs");
168 &format
!("maybe move this module `{}` to its own \
169 directory via `{}`", src_path
.display(),
170 dest_path
.display()));
174 if paths
.path_exists
{
176 &format
!("... or maybe `use` the module `{}` instead \
177 of possibly redeclaring it",
185 pub(super) fn submod_path_from_attr(attrs
: &[Attribute
], dir_path
: &Path
) -> Option
<PathBuf
> {
186 if let Some(s
) = attr
::first_attr_value_str_by_name(attrs
, sym
::path
) {
189 // On windows, the base path might have the form
190 // `\\?\foo\bar` in which case it does not tolerate
191 // mixed `/` and `\` separators, so canonicalize
194 let s
= s
.replace("/", "\\");
195 Some(dir_path
.join(&*s
))
201 /// Returns a path to a module.
202 pub(super) fn default_submod_path(
204 relative
: Option
<ast
::Ident
>,
206 source_map
: &SourceMap
) -> ModulePath
208 // If we're in a foo.rs file instead of a mod.rs file,
209 // we need to look for submodules in
210 // `./foo/<id>.rs` and `./foo/<id>/mod.rs` rather than
211 // `./<id>.rs` and `./<id>/mod.rs`.
212 let relative_prefix_string
;
213 let relative_prefix
= if let Some(ident
) = relative
{
214 relative_prefix_string
= format
!("{}{}", ident
.name
, path
::MAIN_SEPARATOR
);
215 &relative_prefix_string
220 let mod_name
= id
.name
.to_string();
221 let default_path_str
= format
!("{}{}.rs", relative_prefix
, mod_name
);
222 let secondary_path_str
= format
!("{}{}{}mod.rs",
223 relative_prefix
, mod_name
, path
::MAIN_SEPARATOR
);
224 let default_path
= dir_path
.join(&default_path_str
);
225 let secondary_path
= dir_path
.join(&secondary_path_str
);
226 let default_exists
= source_map
.file_exists(&default_path
);
227 let secondary_exists
= source_map
.file_exists(&secondary_path
);
229 let result
= match (default_exists
, secondary_exists
) {
230 (true, false) => Ok(ModulePathSuccess
{
232 directory_ownership
: DirectoryOwnership
::Owned
{
236 (false, true) => Ok(ModulePathSuccess
{
237 path
: secondary_path
,
238 directory_ownership
: DirectoryOwnership
::Owned
{
242 (false, false) => Err(Error
::FileNotFoundForModule
{
243 mod_name
: mod_name
.clone(),
244 default_path
: default_path_str
,
245 secondary_path
: secondary_path_str
,
246 dir_path
: dir_path
.display().to_string(),
248 (true, true) => Err(Error
::DuplicatePaths
{
249 mod_name
: mod_name
.clone(),
250 default_path
: default_path_str
,
251 secondary_path
: secondary_path_str
,
257 path_exists
: default_exists
|| secondary_exists
,
262 /// Reads a module from a source file.
266 directory_ownership
: DirectoryOwnership
,
269 ) -> PResult
<'a
, (Mod
, Vec
<Attribute
>)> {
270 let mut included_mod_stack
= self.sess
.included_mod_stack
.borrow_mut();
271 if let Some(i
) = included_mod_stack
.iter().position(|p
| *p
== path
) {
272 let mut err
= String
::from("circular modules: ");
273 let len
= included_mod_stack
.len();
274 for p
in &included_mod_stack
[i
.. len
] {
275 err
.push_str(&p
.to_string_lossy());
276 err
.push_str(" -> ");
278 err
.push_str(&path
.to_string_lossy());
279 return Err(self.span_fatal(id_sp
, &err
[..]));
281 included_mod_stack
.push(path
.clone());
282 drop(included_mod_stack
);
285 new_sub_parser_from_file(self.sess
, &path
, directory_ownership
, Some(name
), id_sp
);
286 p0
.cfg_mods
= self.cfg_mods
;
287 let mod_inner_lo
= p0
.token
.span
;
288 let mod_attrs
= p0
.parse_inner_attributes()?
;
289 let mut m0
= p0
.parse_mod_items(&token
::Eof
, mod_inner_lo
)?
;
291 self.sess
.included_mod_stack
.borrow_mut().pop();
295 fn push_directory(&mut self, id
: Ident
, attrs
: &[Attribute
]) {
296 if let Some(path
) = attr
::first_attr_value_str_by_name(attrs
, sym
::path
) {
297 self.directory
.path
.to_mut().push(&*path
.as_str());
298 self.directory
.ownership
= DirectoryOwnership
::Owned { relative: None }
;
300 // We have to push on the current module name in the case of relative
301 // paths in order to ensure that any additional module paths from inline
302 // `mod x { ... }` come after the relative extension.
304 // For example, a `mod z { ... }` inside `x/y.rs` should set the current
305 // directory path to `/x/y/z`, not `/x/z` with a relative offset of `y`.
306 if let DirectoryOwnership
::Owned { relative }
= &mut self.directory
.ownership
{
307 if let Some(ident
) = relative
.take() { // remove the relative offset
308 self.directory
.path
.to_mut().push(&*ident
.as_str());
311 self.directory
.path
.to_mut().push(&*id
.as_str());