about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMazdak Farrokhzad <twingoow@gmail.com>2020-03-08 09:28:46 +0100
committerMazdak Farrokhzad <twingoow@gmail.com>2020-03-18 15:08:25 +0100
commitca098b16a4114fd96a4059ba3f807d33dde5ef07 (patch)
tree9fb703efa6852016b34fdcd7c5d14a061d495b68
parentdfcefa49ed5ce5018d279a8d1a60744da67c80c8 (diff)
downloadrust-ca098b16a4114fd96a4059ba3f807d33dde5ef07.tar.gz
rust-ca098b16a4114fd96a4059ba3f807d33dde5ef07.zip
detach submod_path from Parser
-rw-r--r--src/librustc_parse/parser/diagnostics.rs31
-rw-r--r--src/librustc_parse/parser/module.rs348
2 files changed, 192 insertions, 187 deletions
diff --git a/src/librustc_parse/parser/diagnostics.rs b/src/librustc_parse/parser/diagnostics.rs
index 8e52bb16147..87255386b9e 100644
--- a/src/librustc_parse/parser/diagnostics.rs
+++ b/src/librustc_parse/parser/diagnostics.rs
@@ -18,7 +18,6 @@ use rustc_span::{MultiSpan, Span, SpanSnippetError, DUMMY_SP};
 
 use log::{debug, trace};
 use std::mem;
-use std::path::PathBuf;
 
 const TURBOFISH: &str = "use `::<...>` instead of `<...>` to specify type arguments";
 
@@ -41,42 +40,12 @@ pub(super) fn dummy_arg(ident: Ident) -> Param {
 }
 
 pub enum Error {
-    FileNotFoundForModule { mod_name: String, default_path: PathBuf },
-    DuplicatePaths { mod_name: String, default_path: String, secondary_path: String },
     UselessDocComment,
 }
 
 impl Error {
     fn span_err(self, sp: impl Into<MultiSpan>, handler: &Handler) -> DiagnosticBuilder<'_> {
         match self {
-            Error::FileNotFoundForModule { ref mod_name, ref default_path } => {
-                let mut err = struct_span_err!(
-                    handler,
-                    sp,
-                    E0583,
-                    "file not found for module `{}`",
-                    mod_name,
-                );
-                err.help(&format!(
-                    "to create the module `{}`, create file \"{}\"",
-                    mod_name,
-                    default_path.display(),
-                ));
-                err
-            }
-            Error::DuplicatePaths { ref mod_name, ref default_path, ref secondary_path } => {
-                let mut err = struct_span_err!(
-                    handler,
-                    sp,
-                    E0584,
-                    "file for module `{}` found at both {} and {}",
-                    mod_name,
-                    default_path,
-                    secondary_path,
-                );
-                err.help("delete or rename one of them to remove the ambiguity");
-                err
-            }
             Error::UselessDocComment => {
                 let mut err = struct_span_err!(
                     handler,
diff --git a/src/librustc_parse/parser/module.rs b/src/librustc_parse/parser/module.rs
index d203e665c95..a30d6da281a 100644
--- a/src/librustc_parse/parser/module.rs
+++ b/src/librustc_parse/parser/module.rs
@@ -1,4 +1,3 @@
-use super::diagnostics::Error;
 use super::item::ItemInfo;
 use super::Parser;
 
@@ -7,18 +6,19 @@ use crate::{new_sub_parser_from_file, DirectoryOwnership};
 use rustc_ast::ast::{self, Attribute, Crate, Ident, ItemKind, Mod};
 use rustc_ast::attr;
 use rustc_ast::token::{self, TokenKind};
-use rustc_errors::PResult;
-use rustc_span::source_map::{FileName, SourceMap, Span, DUMMY_SP};
+use rustc_errors::{struct_span_err, PResult};
+use rustc_session::parse::ParseSess;
+use rustc_span::source_map::{FileName, Span, DUMMY_SP};
 use rustc_span::symbol::sym;
 
 use std::path::{self, Path, PathBuf};
 
 /// Information about the path to a module.
 // Public for rustfmt usage.
-pub struct ModulePath {
+pub struct ModulePath<'a> {
     name: String,
     path_exists: bool,
-    pub result: Result<ModulePathSuccess, Error>,
+    pub result: PResult<'a, ModulePathSuccess>,
 }
 
 // Public for rustfmt usage.
@@ -45,8 +45,13 @@ impl<'a> Parser<'a> {
         let (module, mut inner_attrs) = if self.eat(&token::Semi) {
             if in_cfg && self.recurse_into_file_modules {
                 // This mod is in an external file. Let's go get it!
-                let ModulePathSuccess { path, directory_ownership } =
-                    self.submod_path(id, &attrs)?;
+                let ModulePathSuccess { path, directory_ownership } = submod_path(
+                    self.sess,
+                    id,
+                    &attrs,
+                    self.directory.ownership,
+                    &self.directory.path,
+                )?;
                 self.eval_src_mod(path, directory_ownership, id.to_string(), id.span)?
             } else {
                 (ast::Mod { inner: DUMMY_SP, items: Vec::new(), inline: false }, Vec::new())
@@ -96,155 +101,6 @@ impl<'a> Parser<'a> {
         Ok(Mod { inner: inner_lo.to(hi), items, inline: true })
     }
 
-    fn submod_path(
-        &mut self,
-        id: ast::Ident,
-        outer_attrs: &[Attribute],
-    ) -> PResult<'a, ModulePathSuccess> {
-        if let Some(path) = Parser::submod_path_from_attr(outer_attrs, &self.directory.path) {
-            let directory_ownership = match path.file_name().and_then(|s| s.to_str()) {
-                // All `#[path]` files are treated as though they are a `mod.rs` file.
-                // This means that `mod foo;` declarations inside `#[path]`-included
-                // files are siblings,
-                //
-                // Note that this will produce weirdness when a file named `foo.rs` is
-                // `#[path]` included and contains a `mod foo;` declaration.
-                // If you encounter this, it's your own darn fault :P
-                Some(_) => DirectoryOwnership::Owned { relative: None },
-                _ => DirectoryOwnership::UnownedViaMod,
-            };
-            return Ok(ModulePathSuccess { directory_ownership, path });
-        }
-
-        let relative = match self.directory.ownership {
-            DirectoryOwnership::Owned { relative } => relative,
-            DirectoryOwnership::UnownedViaBlock | DirectoryOwnership::UnownedViaMod => None,
-        };
-        let paths =
-            Parser::default_submod_path(id, relative, &self.directory.path, self.sess.source_map());
-
-        match self.directory.ownership {
-            DirectoryOwnership::Owned { .. } => {
-                paths.result.map_err(|err| self.span_fatal_err(id.span, err))
-            }
-            DirectoryOwnership::UnownedViaBlock => self.error_decl_mod_in_block(id.span, paths),
-            DirectoryOwnership::UnownedViaMod => self.error_cannot_declare_mod_here(id.span, paths),
-        }
-    }
-
-    fn error_decl_mod_in_block<T>(&self, id_sp: Span, paths: ModulePath) -> PResult<'a, T> {
-        let msg =
-            "Cannot declare a non-inline module inside a block unless it has a path attribute";
-        let mut err = self.struct_span_err(id_sp, msg);
-        if paths.path_exists {
-            let msg = format!("Maybe `use` the module `{}` instead of redeclaring it", paths.name);
-            err.span_note(id_sp, &msg);
-        }
-        Err(err)
-    }
-
-    fn error_cannot_declare_mod_here<T>(&self, id_sp: Span, paths: ModulePath) -> PResult<'a, T> {
-        let mut err = self.struct_span_err(id_sp, "cannot declare a new module at this location");
-        if !id_sp.is_dummy() {
-            if let FileName::Real(src_path) = self.sess.source_map().span_to_filename(id_sp) {
-                if let Some(stem) = src_path.file_stem() {
-                    let mut dest_path = src_path.clone();
-                    dest_path.set_file_name(stem);
-                    dest_path.push("mod.rs");
-                    err.span_note(
-                        id_sp,
-                        &format!(
-                            "maybe move this module `{}` to its own \
-                                    directory via `{}`",
-                            src_path.display(),
-                            dest_path.display()
-                        ),
-                    );
-                }
-            }
-        }
-        if paths.path_exists {
-            err.span_note(
-                id_sp,
-                &format!(
-                    "... or maybe `use` the module `{}` instead \
-                                of possibly redeclaring it",
-                    paths.name
-                ),
-            );
-        }
-        Err(err)
-    }
-
-    /// Derive a submodule path from the first found `#[path = "path_string"]`.
-    /// The provided `dir_path` is joined with the `path_string`.
-    // Public for rustfmt usage.
-    pub fn submod_path_from_attr(attrs: &[Attribute], dir_path: &Path) -> Option<PathBuf> {
-        // Extract path string from first `#[path = "path_string"]` attribute.
-        let path_string = attr::first_attr_value_str_by_name(attrs, sym::path)?;
-        let path_string = path_string.as_str();
-
-        // On windows, the base path might have the form
-        // `\\?\foo\bar` in which case it does not tolerate
-        // mixed `/` and `\` separators, so canonicalize
-        // `/` to `\`.
-        #[cfg(windows)]
-        let path_string = path_string.replace("/", "\\");
-
-        Some(dir_path.join(&*path_string))
-    }
-
-    /// Returns a path to a module.
-    // Public for rustfmt usage.
-    pub fn default_submod_path(
-        id: ast::Ident,
-        relative: Option<ast::Ident>,
-        dir_path: &Path,
-        source_map: &SourceMap,
-    ) -> ModulePath {
-        // If we're in a foo.rs file instead of a mod.rs file,
-        // we need to look for submodules in
-        // `./foo/<id>.rs` and `./foo/<id>/mod.rs` rather than
-        // `./<id>.rs` and `./<id>/mod.rs`.
-        let relative_prefix_string;
-        let relative_prefix = if let Some(ident) = relative {
-            relative_prefix_string = format!("{}{}", ident.name, path::MAIN_SEPARATOR);
-            &relative_prefix_string
-        } else {
-            ""
-        };
-
-        let mod_name = id.name.to_string();
-        let default_path_str = format!("{}{}.rs", relative_prefix, mod_name);
-        let secondary_path_str =
-            format!("{}{}{}mod.rs", relative_prefix, mod_name, path::MAIN_SEPARATOR);
-        let default_path = dir_path.join(&default_path_str);
-        let secondary_path = dir_path.join(&secondary_path_str);
-        let default_exists = source_map.file_exists(&default_path);
-        let secondary_exists = source_map.file_exists(&secondary_path);
-
-        let result = match (default_exists, secondary_exists) {
-            (true, false) => Ok(ModulePathSuccess {
-                path: default_path,
-                directory_ownership: DirectoryOwnership::Owned { relative: Some(id) },
-            }),
-            (false, true) => Ok(ModulePathSuccess {
-                path: secondary_path,
-                directory_ownership: DirectoryOwnership::Owned { relative: None },
-            }),
-            (false, false) => {
-                Err(Error::FileNotFoundForModule { mod_name: mod_name.clone(), default_path })
-            }
-            (true, true) => Err(Error::DuplicatePaths {
-                mod_name: mod_name.clone(),
-                default_path: default_path_str,
-                secondary_path: secondary_path_str,
-            }),
-        };
-
-        ModulePath { name: mod_name, path_exists: default_exists || secondary_exists, result }
-    }
-
     /// Reads a module from a source file.
     fn eval_src_mod(
         &mut self,
@@ -308,3 +164,183 @@ impl<'a> Parser<'a> {
         }
     }
 }
+
+fn submod_path<'a>(
+    sess: &'a ParseSess,
+    id: ast::Ident,
+    outer_attrs: &[Attribute],
+    directory_ownership: DirectoryOwnership,
+    dir_path: &Path,
+) -> PResult<'a, ModulePathSuccess> {
+    if let Some(path) = submod_path_from_attr(outer_attrs, dir_path) {
+        let directory_ownership = match path.file_name().and_then(|s| s.to_str()) {
+            // All `#[path]` files are treated as though they are a `mod.rs` file.
+            // This means that `mod foo;` declarations inside `#[path]`-included
+            // files are siblings,
+            //
+            // Note that this will produce weirdness when a file named `foo.rs` is
+            // `#[path]` included and contains a `mod foo;` declaration.
+            // If you encounter this, it's your own darn fault :P
+            Some(_) => DirectoryOwnership::Owned { relative: None },
+            _ => DirectoryOwnership::UnownedViaMod,
+        };
+        return Ok(ModulePathSuccess { directory_ownership, path });
+    }
+
+    let relative = match directory_ownership {
+        DirectoryOwnership::Owned { relative } => relative,
+        DirectoryOwnership::UnownedViaBlock | DirectoryOwnership::UnownedViaMod => None,
+    };
+    let ModulePath { path_exists, name, result } =
+        default_submod_path(sess, id, relative, dir_path);
+    match directory_ownership {
+        DirectoryOwnership::Owned { .. } => Ok(result?),
+        DirectoryOwnership::UnownedViaBlock => {
+            let _ = result.map_err(|mut err| err.cancel());
+            error_decl_mod_in_block(sess, id.span, path_exists, &name)
+        }
+        DirectoryOwnership::UnownedViaMod => {
+            let _ = result.map_err(|mut err| err.cancel());
+            error_cannot_declare_mod_here(sess, id.span, path_exists, &name)
+        }
+    }
+}
+
+fn error_decl_mod_in_block<'a, T>(
+    sess: &'a ParseSess,
+    id_sp: Span,
+    path_exists: bool,
+    name: &str,
+) -> PResult<'a, T> {
+    let msg = "Cannot declare a non-inline module inside a block unless it has a path attribute";
+    let mut err = sess.span_diagnostic.struct_span_err(id_sp, msg);
+    if path_exists {
+        let msg = format!("Maybe `use` the module `{}` instead of redeclaring it", name);
+        err.span_note(id_sp, &msg);
+    }
+    Err(err)
+}
+
+fn error_cannot_declare_mod_here<'a, T>(
+    sess: &'a ParseSess,
+    id_sp: Span,
+    path_exists: bool,
+    name: &str,
+) -> PResult<'a, T> {
+    let mut err =
+        sess.span_diagnostic.struct_span_err(id_sp, "cannot declare a new module at this location");
+    if !id_sp.is_dummy() {
+        if let FileName::Real(src_path) = sess.source_map().span_to_filename(id_sp) {
+            if let Some(stem) = src_path.file_stem() {
+                let mut dest_path = src_path.clone();
+                dest_path.set_file_name(stem);
+                dest_path.push("mod.rs");
+                err.span_note(
+                    id_sp,
+                    &format!(
+                        "maybe move this module `{}` to its own \
+                                directory via `{}`",
+                        src_path.display(),
+                        dest_path.display()
+                    ),
+                );
+            }
+        }
+    }
+    if path_exists {
+        err.span_note(
+            id_sp,
+            &format!("... or maybe `use` the module `{}` instead of possibly redeclaring it", name),
+        );
+    }
+    Err(err)
+}
+
+/// Derive a submodule path from the first found `#[path = "path_string"]`.
+/// The provided `dir_path` is joined with the `path_string`.
+// Public for rustfmt usage.
+pub fn submod_path_from_attr(attrs: &[Attribute], dir_path: &Path) -> Option<PathBuf> {
+    // Extract path string from first `#[path = "path_string"]` attribute.
+    let path_string = attr::first_attr_value_str_by_name(attrs, sym::path)?;
+    let path_string = path_string.as_str();
+
+    // On windows, the base path might have the form
+    // `\\?\foo\bar` in which case it does not tolerate
+    // mixed `/` and `\` separators, so canonicalize
+    // `/` to `\`.
+    #[cfg(windows)]
+    let path_string = path_string.replace("/", "\\");
+
+    Some(dir_path.join(&*path_string))
+}
+
+/// Returns a path to a module.
+// Public for rustfmt usage.
+pub fn default_submod_path<'a>(
+    sess: &'a ParseSess,
+    id: ast::Ident,
+    relative: Option<ast::Ident>,
+    dir_path: &Path,
+) -> ModulePath<'a> {
+    // If we're in a foo.rs file instead of a mod.rs file,
+    // we need to look for submodules in
+    // `./foo/<id>.rs` and `./foo/<id>/mod.rs` rather than
+    // `./<id>.rs` and `./<id>/mod.rs`.
+    let relative_prefix_string;
+    let relative_prefix = if let Some(ident) = relative {
+        relative_prefix_string = format!("{}{}", ident.name, path::MAIN_SEPARATOR);
+        &relative_prefix_string
+    } else {
+        ""
+    };
+
+    let mod_name = id.name.to_string();
+    let default_path_str = format!("{}{}.rs", relative_prefix, mod_name);
+    let secondary_path_str =
+        format!("{}{}{}mod.rs", relative_prefix, mod_name, path::MAIN_SEPARATOR);
+    let default_path = dir_path.join(&default_path_str);
+    let secondary_path = dir_path.join(&secondary_path_str);
+    let default_exists = sess.source_map().file_exists(&default_path);
+    let secondary_exists = sess.source_map().file_exists(&secondary_path);
+
+    let result = match (default_exists, secondary_exists) {
+        (true, false) => Ok(ModulePathSuccess {
+            path: default_path,
+            directory_ownership: DirectoryOwnership::Owned { relative: Some(id) },
+        }),
+        (false, true) => Ok(ModulePathSuccess {
+            path: secondary_path,
+            directory_ownership: DirectoryOwnership::Owned { relative: None },
+        }),
+        (false, false) => {
+            let mut err = struct_span_err!(
+                sess.span_diagnostic,
+                id.span,
+                E0583,
+                "file not found for module `{}`",
+                mod_name,
+            );
+            err.help(&format!(
+                "to create the module `{}`, create file \"{}\"",
+                mod_name,
+                default_path.display(),
+            ));
+            Err(err)
+        }
+        (true, true) => {
+            let mut err = struct_span_err!(
+                sess.span_diagnostic,
+                id.span,
+                E0584,
+                "file for module `{}` found at both {} and {}",
+                mod_name,
+                default_path_str,
+                secondary_path_str,
+            );
+            err.help("delete or rename one of them to remove the ambiguity");
+            Err(err)
+        }
+    };
+
+    ModulePath { name: mod_name, path_exists: default_exists || secondary_exists, result }
+}